14

I have a spring-boot application for which am trying to create unit testcases. Below is the code that I am trying to run, I don't have any configuration file that I have (used only annotations) so the main class that loads all the configuration is ElastSearchBootApplication class. For some reason I see the below error.

@ComponentScan(basePackages = "com.somename")
@SpringBootApplication
@EnableScheduling
public class ElastSearchBootApplication {

    private static final Logger LOG = LoggerFactory.getLogger(ElastSearchBootApplication.class);

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

    @Autowired
    private ElastSearchLogLevel logsSearch;

    @Scheduled(fixedRate = 120000)
public void scheduledSearchLogs() {
        ...

Test class :

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ElastSearchBootApplication.class)
public class LogSearchTest {

    @Mock
    private RestHighLevelClient client;
    @Mock
      private ExecutorService ALERT_POOL;

    @Before
    public void setUp() throws Exception {
          client = mock(RestHighLevelClient.class);
        ALERT_POOL = mock(ExecutorService.class);

        try {
            when(client.search(anyObject())).thenReturn(getResponse());
        } catch (Exception e) {
            // I see NullPointerException but both the instances are available here
            e.printStackTrace();
        }
        doNothing().when(ALERT_POOL.invokeAll(anyObject()));
    }

I see the below error when trying to run the spring-boot test :

org.springframework.boot.test.context.SpringBootTestContextBootstrapper buildDefaultMergedContextConfiguration
INFO: Neither @ContextConfiguration nor @ContextHierarchy found for test class [com.somename.search.LogSearchTest], using SpringBootContextLoader
org.springframework.test.context.support.AbstractContextLoader generateDefaultLocations
INFO: Could not detect default resource locations for test class [com.somename.search.LogSearchTest]: no resource found for suffixes {-context.xml, Context.groovy}.
org.springframework.test.context.support.AnnotationConfigContextLoaderUtils detectDefaultConfigurationClasses
INFO: Could not detect default configuration classes for test class [com.somename.search.LogSearchTest]: LogSearchTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
  1. I see that @SpringBootTest is used for integration tests, so can I use it for unit tests ? If I remove it then I get another set of exception that looks similar though. I would be more interested in running this testcase without SpringBootTest

  2. Why my test case say some configuration is missing. The samples online talk about xml files which I don't have. So what am I missing here ?

  3. Can I dynamically pass the value for fixedRate from Environment and put it like @Scheduled(fixedRate = ${some.value.defined})

UPDATE

I can run the test but without the proper order. Ideally i expect setUp to run first. But its running second. Also the line when(client.search(anyObject())).thenReturn(getResponse()); is failing and i dont get the reason...

Raghuveer
  • 2,859
  • 7
  • 34
  • 66
  • Replace your `@RunWith` with `@RunWith(SpringJUnit4ClassRunner.class)` on the test class. You don't need `@ ContextConfiguration` and `@SpringBootTest` for the unit test class. – Madhu Bhat Sep 11 '18 at 11:46
  • Without `@ContextConfiguration(classes = ElastSearchBootApplication.class)` configuration will not be detected. However I will update the code now to show you the latest. For some reasonmy mocking is failing at `when(client.search(anyObject())).thenReturn(getResponse());` – Raghuveer Sep 11 '18 at 11:53
  • 1
    Also, are you trying to mock the elasticsearch client? Here it says that it can't be mocked https://discuss.elastic.co/t/resthighlevelclient-mocking/123027 – Madhu Bhat Sep 11 '18 at 13:32

2 Answers2

27

You have to add the annotation @ContextConfiguration to your test class to specify configuration file.

@ContextConfiguration(classes = ElastSearchBootApplication.class)
Gaurav Srivastav
  • 2,381
  • 1
  • 15
  • 18
  • I have added it now it goes a little further now instead of starting with `setup()` it directly runs my testcases inspite of `@Before` on it. – Raghuveer Sep 11 '18 at 11:28
  • Where you added this annotation? – Gaurav Srivastav Sep 11 '18 at 14:15
  • Nope, the junit `@Before` is not working so I removed the code in `setup` and put in test menthod itself, which solves my one of the problems. as I said the code within try block is throwing exception for some reason when the code goes inside elasticsearch API I get a `NullPointerException` – Raghuveer Sep 12 '18 at 05:27
  • This works, but not sure why it wont detect groovy package. com.y.u.n.x.api.acceptance.tests.acceptance com.y.u.n.x.acceptance.tests.acceptance --> My mail class resides here – Ravi Macha Nov 05 '19 at 18:23
2

Try this:

@RunWith(SpringRunner.class)
@SpringBootTest
public class LogSearchTest {

  @MockBean
  private RestHighLevelClient client;
  @MockBean
  private ExecutorService ALERT_POOL;

  @Before
  public void setUp() throws Exception {
   try {
        when(client.search(anyObject())).thenReturn(getResponse());
    } catch (Exception e) {
        // I see NullPointerException but both the instances are available here
        e.printStackTrace();
    }
    doNothing().when(ALERT_POOL.invokeAll(anyObject()));
  }
borino
  • 1,720
  • 1
  • 16
  • 24
  • thanks for reply. Previously this is what I had when I started off with the issue. I have actually updated the code now. Its the issue with `SpringBootTest` I think, somehow not reading test ENV and its suppose to run `setUp` first. – Raghuveer Sep 11 '18 at 12:08
  • If you wann using `@ContextConfiguration` you should create class `@Configuration` where you declare all required beans in your case : repeat configs from main lcass `@ComponentScan(basePackages = "com.somename")` and `@EnableScheduling` . You got error "Could not detect default configuration..." because of `ElastSearchBootApplication` is not `@Configuration` class. Good topic about it: https://spring.io/blog/2011/06/21/spring-3-1-m2-testing-with-configuration-classes-and-profiles – borino Sep 11 '18 at 12:13
  • Since I added `@ContextConfiguration` my testcase is able to autowire things its not expecting a separate `@Configuration` and I don't need `@EnableScheduling`. – Raghuveer Sep 12 '18 at 05:30
  • 1
    If you wanna minimal context better choice is using separate configuration class, otherwise for example you will scan whole package via `@ComponentScan(basePackages = "com.somename")` instead of just create one required service for test. What expected result of your questions???? Maybe you have example on github it will be easier to help you. – borino Sep 12 '18 at 05:49