Reputation: 199
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.
Upvotes: 2
Views: 5057
Reputation: 1231
I'm trying to answer your question using Mockito and Junit with MockMvc Testing method.
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);
}
}
}
Upvotes: 0
Reputation: 22384
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));
}
}
Upvotes: 6
Reputation: 7273
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.
Upvotes: 1