2

Im trying to do unit tests for a Rest Controller. I did a stub(~mock) for the manager to the database acces and it works well. My only issue is that when I start my unit test it doesn't start the Application.

How can I start the application from my unit test ?

I'm using spring 4.2.3, spring boot 1.3.7, junit 4.12.

Here are my classes :

TestRestController

@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(locations = "classpath:/META-INF/spring/mvc/mvc-test-context.xml") public class RestControllerTest extends AbstractTransitionnalTest { @Autowired private IManager Manager; @Test public void getTestSingleItem(){ Item itm = myTestItemPreInitiallized; Manager.save(itm); List<Map> apiResponse = restTemplate.getForObject(networkAddress + "/items", List.class); // Assertions on apiResponse } } 

RestController:

@RestController @RequestMapping("/items") class RestController { @Autowired private IManager Manager; // Controller content } 

Beans in mvc-test-context.xml

<bean id="IManager" class="com.service.ManagerStub"> </bean> <bean id="RestController" class="com.controller.RestController"> </bean> 

Application class that contains the main

@Configuration @EnableAutoConfiguration @EnableTransactionManagement @ImportResource({ "classpath:/META-INF/spring/context-application.xml" }) public class Application { 

If I run it as it is now the application class isn't started and i get the following erreor : I/O error on GET request for adress:Connection refused

If you don't have the exact solution or would like to propose another way to do this or a workaround, what I wish for is to have the ManagerStub to be inserted in the @Autowired manager instead Manager class only when I launch my test.

3 Answers 3

6

We can use the combination of MockitoJUnitRunner and Spring's MockMvcBuilders class to write the unit test the Spring REST Controller.

I have made changed to your code and refer it below to write the JUnits for your REST Controller.

import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import com.fasterxml.jackson.databind.ObjectMapper; import biz.cogitare.framework.controllers.advices.ExceptionControllerAdvice; @RunWith(MockitoJUnitRunner.class) public class RestControllerTest { private MockMvc mockMvc; private Item item; private String itemJSON; @Mock private Manager manager; @InjectMocks private RestController restController = new RestController(); @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mockMvc = MockMvcBuilders.standaloneSetup(restController) .setMessageConverters(new MappingJackson2HttpMessageConverter()); Item item = myTestItemPreInitiallized; itemJSON = new ObjectMapper().writeValueAsString(itm); } @Test public void testQuerySuccess() throws Exception { List<Item> items = new ArrayList<>(); items.add(item); Mockito.when(manager.findItems()).thenReturn(items); mockMvc.perform(get("/items?itemId=1").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); //.andExpect(jsonPath("$[0].id", is(1))) //.andExpect(jsonPath("$[0].name", is("xyz"))); Mockito.verify(manager).findItems(); } @Test public void testInsertSuccess() throws Exception { Mockito.when(manager.insertOrUpdate(Mockito.any(Item.class))).thenReturn(item); mockMvc.perform(post("/items").contentType(MediaType.APPLICATION_JSON).content(itemJSON) .accept(MediaType.APPLICATION_JSON)).andExpect(status().isCreated()); Mockito.verify(manager).save(Mockito.any(Item.class)); } } 
Sign up to request clarification or add additional context in comments.

Comments

1

I annotate my integrated REST JUnit tests with:

@WebIntegrationTest 

And the actual Application class with

@SpringBootApplication 

(on top of all the annotations that you showed).
Using those annotations, Spring Boot takes care of launching the application with the provided configuration before running the tests.

EDIT: According to the documentation, @WebIntegrationTest is deprecated since 1.4 in favor of @SpringBootTest, but you're using 1.3.7 so no problem.

3 Comments

When I add the annotation @WebIntegrationTest I get the following exception java.lang.IllegalStateException: Failed to load ApplicationContext. I also tried to manually load the application context and it still does not start the main application with these annotations. It may because the context is loaded manually, or there is something I forgot in the context file.
Did you use both annotations or just the first one?
I tried using the first one and both at the same time, leads to the same result. I also tried removing the inheritance from AbstractTransitionnalTest which has the annotation @Transactionnal and I still got the same exception
0

I'm trying to answer your question using Mockito and Junit with MockMvc Testing method.

  • Here I've make some changes in your present test class.

TestRestController

import static org.junit.Assert.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import com.fasterxml.jackson.databind.ObjectMapper; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(locations = "classpath:/META-INF/spring/mvc/mvc-test-context.xml") public class RestControllerTest extends AbstractTransitionnalTest { @Mock private IManager Manager; private MockMvc mockMvc; @Before public void setUp() throws Exception { initMocks(this);// this is needed for inititalization of mocks, if you use @Mock RestController controller = new RestController(manager); mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); } @Test public void getTestSingleItem(){ Item itm = yourTestItemPreInitiallized; Mockito.when(manager.save(Mockito.any(Item.class))).thenReturn(itm); mockMvc.perform(MockMvcRequestBuilders.post("/items") .content(asJsonString(app)) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().contentType("application/json;charset=UTF-8")); } public static String asJsonString(final Object obj) { try { return new ObjectMapper().writeValueAsString(obj); } catch (Exception e) { throw new RuntimeException(e); } } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.