1

I am trying to do integration tests which include the execution of an ApplicationRunner.

I use @SpringBootTest, and when the context is initialized, the ApplicationRunner is automatically launched, which is okay.

What I want to achieve is to inject a Mock in the ApplicationRunner AND configure that mock BEFORE the ApplicationRunner is executed.

It doesn't work if I configure the mock IN the test, because by the time the test is executed, the Spring context has already been initialized and the ApplicationRunner has already been executed.

Is there a way to configure the mock after the Spring context has been initialized, and before the ApplicationRunner is executed?

mre
  • 43,520
  • 33
  • 120
  • 170
Mr.Eddart
  • 10,050
  • 13
  • 49
  • 77
  • could you please add your source about ApplicationRunner implementation and test – nekperu15739 May 23 '20 at 23:21
  • The question is quite conceptual, the specific implementations should be irrelevant... – Mr.Eddart May 23 '20 at 23:36
  • 1
    i suppose that you are using springBootTests without configure the specific class that you want to test. So spring start all bean in context including the dependency you want to mock. to avoid that you must specify only the bean that you want test and all the dependencies as mockBean. However, without see source is imposible confirm it. – nekperu15739 May 24 '20 at 00:41
  • Yes!! I want to mock a dependency, AND configure that mock before the ApplicationRunner is executed. I am having trouble achieving this because the ApplicationRunner is executed before the flow control arrives to the Test class. – Mr.Eddart May 25 '20 at 08:39
  • @Mr.Eddart Actually I still didn't understand you completely. However, I added the answer that I implied for. So you can see whether it satisfies your need or else how we can improve that to cater to your need. Thnx. – Supun Wijerathne May 25 '20 at 13:39

2 Answers2

0

If you have a bean dependency for your ApplicationRunner class, You can mock it as below.

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest   
public class ApplicationRunnerTest {
    @MockBean
    private final Dependency dependency;
    @Autowired
    private final ApplicationRunner applicationRunner;

    @Before
    public void setUp() throws Exception {
    }

    @Test
    public void testMethod() {
    }
}
Supun Wijerathne
  • 11,964
  • 10
  • 61
  • 87
  • When providing a code snippet, it's helpful to include the import statements. :) – mre May 25 '20 at 13:46
  • @mre agree.. In this situation just thought it's pretty implicit. Anyway added.. thnx :) – Supun Wijerathne May 25 '20 at 13:51
  • Thanks, but I specified that I want to not only mock the dependency, but ALSO configure its behavior BEFORE the execution of the ApplicationRunner (which is executed before the Test methods are invoked, and thus before I have had any chance to configure the mock)... – Mr.Eddart May 25 '20 at 16:09
  • @Mr.Eddart your point is quite unclear. May I ask how its getting executed before test methods are invoked? – Supun Wijerathne May 25 '20 at 16:41
  • @Mr.Eddart pl pls provide your code to understand the execution of your ApplicationRunner since the scenario you mention sounds quite weird – Supun Wijerathne May 25 '20 at 16:43
0

Hope this answers your question

Here webApplicationContext is initialised whenever we try to execute a test case as @Before get initiated which calls setUp() of AbstractTest class which has initialisation logic of webApplicationContext

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Main.class)
@WebAppConfiguration
public abstract class AbstractTest {

   protected MockMvc mvc;
   @Autowired
   WebApplicationContext webApplicationContext;

   protected void setUp() {
      mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
   }

   protected String mapToJson(Object obj) throws JsonProcessingException {
      ObjectMapper objectMapper = new ObjectMapper();
      return objectMapper.writeValueAsString(obj);
   }
   protected <T> T mapFromJson(String json, Class<T> clazz)
      throws JsonParseException, JsonMappingException, IOException {

      ObjectMapper objectMapper = new ObjectMapper();
      return objectMapper.readValue(json, clazz);
   }
}


public class UserControllerTest extends AbstractTest {
   @Override
   @Before
   public void setUp() {
      super.setUp();
   }
   @Test
   public void testGet() throws Exception {
      String uri = “/url”;
      MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get(uri)
         .accept(MediaType.APPLICATION_JSON_VALUE)).andReturn();

      int status = mvcResult.getResponse().getStatus();
      assertEquals(200, status);
   }

}

Main Spring boot class

@SpringBootApplication
public class Main extends SpringBootServletInitializer{

    private Logger LOGGER = (Logger) LoggerFactory.getLogger(FactsMain.class);

    @Value("${facts.trustCertPath}")
    private String trustCertPath;


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

    @Override
     protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
      return application.sources(FactsMain.class);
     }

    @PostConstruct
    public void setSSLPath() {

        LOGGER.info("trustCertPath - " + trustCertPath);
        System.setProperty("javax.net.ssl.trustStore", trustCertPath);
    }
}
abhinav kumar
  • 1,487
  • 1
  • 12
  • 20
  • Thanks. But I think this is not answering the question since it doesn't take in account the execution of the mentioned ApplicationRunner. – Mr.Eddart May 25 '20 at 16:12
  • Instead of SpringRunner you can go for SpringJUnit4ClassRunner as it will enable more features required for testing – abhinav kumar May 25 '20 at 16:32