7

My classes are..

lies in src/intregation-test/java

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = StoreOrderFulfillmentApplication.class)
  @ActiveProfiles("Test")
  public class OrderCreationIntregationTest {

@Autowired
private TestRestTemplate restTemplate;

@MockBean
private OrderRepository orderRepository;

@MockBean
private OrderLineItemRepository orderLineItemRepository;

@MockBean
private InternalEventPublisher internalEventPublisher;

@SuppressWarnings("unchecked")
@Before
public void setup() {
    Mockito.when(orderRepository.findByOfsReferenceId("OFS:GMO:Z100002062-99")).thenReturn(null);
    OrderEntity savedOrder = new OrderEntity();
    savedOrder.setOrderId(1023);
    Mockito.when(orderRepository.save(Mockito.any(OrderEntity.class))).thenReturn(savedOrder);
    Iterable<OrderLineItemEntity> orderLineItemList = prepareOrderLineItemEntityIterable();
    Mockito.when(orderLineItemRepository.save(Mockito.any(Iterable.class))).thenReturn(orderLineItemList);
}

@Test
public void test() throws ParseException {
    FulfillmentOrder fulfillmentOrderRequestVO = new FulfillmentOrder();
    fulfillmentOrderRequestVO = buildFulfillmentOrder();
    String myMessage = "Order Created";
    ResponseEntity<ResponseOrderMessage> responseEntity = restTemplate.postForEntity("/fulfillmentprocessor/orders",
            fulfillmentOrderRequestVO, ResponseOrderMessage.class);
    ResponseOrderMessage responseOrderMessage = responseEntity.getBody();
    assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode());
    assertEquals(myMessage, responseOrderMessage.getMessage());
}

lies in src/main/java

@SpringBootApplication
public class StoreOrderFulfillmentApplication {

public static void main(String[] args) {
    SpringApplication.run(StoreOrderFulfillmentApplication.class, args);
}
}

Now the problem is I wanted to exclude a class from being get component scanned.my this class contains the dependency for apache Kafka. if this class loads while container start up it start looking for kafka running instances. so while running Intregation test I will not be starting my Kafka server,so I wanted to run Intregation test making kafka shutdown.

This I can achieved by adding one line code in StoreOrderFulfillmentApplication class

@ComponentScan(basePackages = "com.tesco.store.order.fulfillment.processor", excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = OrderReceiveEventConfiguration.class))

by addding this line of code StoreOrderFulfillmentApplication class it is excluding OrderReceiveEventConfiguration class from being get component scanned.

now the problem is I not suppose add any test configuration changes in the main code. so I am struggling to do the same exclusion from src/intregation-test/java source folder, is their some way that I can exclude this particular class during container startup code.

but it should not affect my main class code means code inside src/main/java

Any help is Appreciated..

Shobhit Pal
  • 83
  • 1
  • 1
  • 8
  • do you want to test the application behavior when Kafka is down / not running OR you just want to ignore the Kafka part while testing ? – Bond - Java Bond Feb 15 '17 at 09:28
  • Yes @Bond-JavaBond, I wanted to ignore the kafka part while Testing... actually my requirements says, while executing test suite external dependencies should be mocked like database or messaging queue... Reason for doing this in my test box Database and Message queue server are not present, so we have to prepare our test suite like it should not check for connectivity . – Shobhit Pal Feb 15 '17 at 09:52

3 Answers3

7

You can make use of @Conditional as shown below.

  • In application.properties introduce a property say kafka.enabled.
  • Annotate the OrderReceiveEventConfiguration with @Conditional(PropertyCondition.class)
  • Depending on kafka.enabled value viz. true (for normal run) or false (for testing) the OrderReceiveEventConfiguration will be picked up or ignored respectively without changing the code.

Let know in comments in case any more information is required.


Except main @conditional annotation there are set of similar annotation to be used for different cases.

Class conditions

The @ConditionalOnClass and @ConditionalOnMissingClass annotations allows configuration to be included based on the presence or absence of specific classes.

E.g. when OObjectDatabaseTx.class is added to dependencies and there is no OrientWebConfigurer bean we create the configurer.

@Bean
@ConditionalOnWebApplication
@ConditionalOnClass(OObjectDatabaseTx.class)
@ConditionalOnMissingBean(OrientWebConfigurer.class)
public OrientWebConfigurer orientWebConfigurer() {
    return new OrientWebConfigurer();
}

Bean conditions

The @ConditionalOnBean and @ConditionalOnMissingBean annotations allow a bean to be included based on the presence or absence of specific beans. You can use the value attribute to specify beans by type, or name to specify beans by name. The search attribute allows you to limit the ApplicationContext hierarchy that should be considered when searching for beans.

See the example above when we check whether there is no defined bean.

Property conditions

The @ConditionalOnProperty annotation allows configuration to be included based on a Spring Environment property. Use the prefix and name attributes to specify the property that should be checked. By default any property that exists and is not equal to false will be matched. You can also create more advanced checks using the havingValue and matchIfMissing attributes.

@ConditionalOnProperty(value='somebean.enabled', matchIfMissing = true, havingValue="yes")
@Bean 
public SomeBean someBean(){
}

Resource conditions

The @ConditionalOnResource annotation allows configuration to be included only when a specific resource is present.

@ConditionalOnResource(resources = "classpath:init-db.sql") 

Web application conditions

The @ConditionalOnWebApplication and @ConditionalOnNotWebApplication annotations allow configuration to be included depending on whether the application is a 'web application'.

@Configuration
@ConditionalOnWebApplication
public class MyWebMvcAutoConfiguration {...}

SpEL expression conditions

The @ConditionalOnExpression annotation allows configuration to be included based on the result of a SpEL expression.

@ConditionalOnExpression("${rest.security.enabled}==false")
Graham
  • 7,431
  • 18
  • 59
  • 84
Bond - Java Bond
  • 3,972
  • 6
  • 36
  • 59
  • `@Configuration @EnableBinding(Source.class) public class OrderReceiveEventConfiguration { public OrderReceiveEventConfiguration() { } @Value("${spring.outputChannel.timeout.ms}") private long timeoutMs; public long getTimeoutMs() { return timeoutMs; } public void setTimeoutMs(long timeoutMs) { this.timeoutMs = timeoutMs; } }` This is my class can you tell how will i use @Conditional here* – Shobhit Pal Feb 15 '17 at 10:37
  • it should be like this `@Configuration @EnableBinding(Source.class) @Conditional(PropertyCondition.class) public class OrderReceiveEventConfiguration { ... }` – Bond - Java Bond Feb 15 '17 at 12:46
0

You should able able to create a separate config class in your test package

@SpringBootApplication
@ActiveProfiles("Test")
@ComponentScan(basePackages = "com.tesco.store.order.fulfillment.processor", excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = OrderReceiveEventConfiguration.class))
public class StoreOrderFulfillmentApplicationTest {

public static void main(String[] args) {
    SpringApplication.run(StoreOrderFulfillmentApplicationTest.class, args);
}
}

And then in your test class

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = StoreOrderFulfillmentApplicationTest.class)
  @ActiveProfiles("Test")
  public class OrderCreationIntregationTest {

@Autowired
private TestRestTemplate restTemplate;

@MockBean
private OrderRepository orderRepository;

@MockBean
private OrderLineItemRepository orderLineItemRepository;

@MockBean
private InternalEventPublisher internalEventPublisher;

@SuppressWarnings("unchecked")
@Before
public void setup() {
    Mockito.when(orderRepository.findByOfsReferenceId("OFS:GMO:Z100002062-99")).thenReturn(null);
    OrderEntity savedOrder = new OrderEntity();
    savedOrder.setOrderId(1023);
    Mockito.when(orderRepository.save(Mockito.any(OrderEntity.class))).thenReturn(savedOrder);
    Iterable<OrderLineItemEntity> orderLineItemList = prepareOrderLineItemEntityIterable();
    Mockito.when(orderLineItemRepository.save(Mockito.any(Iterable.class))).thenReturn(orderLineItemList);
}

@Test
public void test() throws ParseException {
    FulfillmentOrder fulfillmentOrderRequestVO = new FulfillmentOrder();
    fulfillmentOrderRequestVO = buildFulfillmentOrder();
    String myMessage = "Order Created";
    ResponseEntity<ResponseOrderMessage> responseEntity = restTemplate.postForEntity("/fulfillmentprocessor/orders",
            fulfillmentOrderRequestVO, ResponseOrderMessage.class);
    ResponseOrderMessage responseOrderMessage = responseEntity.getBody();
    assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode());
    assertEquals(myMessage, responseOrderMessage.getMessage());
}
mirmdasif
  • 6,014
  • 2
  • 22
  • 28
  • @mirmdasif, excluding is not working for me either in case of tests (but `@ComponentScan` annotation itself is working - for example basePackages makes diference) – atsu85 Oct 19 '17 at 14:06
0

Create a test application class

@SpringBootApplication
@ComponentScan(basePackages = "com.tesco.store.order.fulfillment.processor", excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = OrderReceiveEventConfiguration.class))
public class TestStoreOrderFulfillmentApplication {

public static void main(String[] args) {
    SpringApplication.run(StoreOrderFulfillmentApplication.class, args);
}
}

Add the following configuration annotation to you test class

@SpringApplicationConfiguration(classes = TestStoreOrderFulfillmentApplication .class)