How to test mvc controller method with http response argument? - java

Can you help me? I need to test this controller method. But don't know what to do with httpservletresponse object.
#Controller
public class HomeController {
#PostMapping("/signout")
public String signOut(HttpServletResponse response){
response.addCookie(new Cookie("auth-token", null));
return "redirect:http://localhost:3000";
}
}
Thank you)

Spring MVC Test provides an effective way to test controllers by performing requests and generating responses through the actual DispatcherServlet.
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher;
#RunWith(SpringRunner.class)
#WebMvcTest(controllers=HomeController.class)
public class HomeControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void testSignOut() throws Exception {
mockMvc.perform(post("/signout"))
.andDo(print())
.andExpect(new ResultMatcher() {
#Override
public void match(MvcResult result) throws Exception {
Assert.assertEquals("http://localhost:3000",result.getResponse().getRedirectedUrl());
}
});
}
}
In case of Spring MVC without spring boot, use standalone MockMvc support
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration // or #ContextConfiguration
public class HomeControllerTest{
#Autowired
private HomeController homeController;
private MockMvc mockMvc;
#Before
public void setup() {
// Setup Spring test in standalone mode
this.mockMvc =
MockMvcBuilders.standaloneSetup(homeController).build();
}

Related

Spring boot WebMvcTest cases keep getting terminated and won't run

When I try using the below code to test the controllers no errors happen, it just says terminated with no logged messages or anything.
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import ....controllers.UserController;
import ....data.response.UserResponse;
import ....models.user.User;
#RunWith(SpringRunner.class)
#WebMvcTest(UserController.class)
public class UserWebMvc {
#Autowired
private MockMvc mvc;
#Test
public void givenEmployees_whenGetEmployees_thenReturnJsonArray() throws Exception {
User alex = new User();
List<UserResponse> allUsers = Arrays.asList(new UserResponse(alex.getId(), alex.getInfo()));
RequestBuilder request = MockMvcRequestBuilders.get("/hello");
MvcResult result = mvc.perform(request).andReturn();
assertEquals(result.getResponse().getContentAsString(), "hello");
// userService.createUser(
// new UserRequest(alex.getInfo().getName(), alex.getInfo().getEmail(), alex.getInfo().getPassword()));
//
}
}
However my test to check that junit is working runs fine, so I'm thinking its something to do with SpringRunner or WebMvc
#SpringBootTest
class BackendApplicationTests {
#Test
void contextLoads() {
assertTrue(false);
}
}
Isn't assertTrue(false) always going to be false? You are basically checking whether false equals true, which will always fail.
Also, from the Spring documentation regarding #WebMvcTest:
Using this annotation will disable full auto-configuration and instead apply only configuration relevant to MVC tests (i.e. #Controller, #ControllerAdvice, #JsonComponent, Converter/GenericConverter, Filter, WebMvcConfigurer and HandlerMethodArgumentResolver beans but not #Component, #Service or #Repository beans).
Using this annotation, it will not scan any beans from the service layer. So if you have a UserService which is injected into the UserController, it will not be found by Spring.
When I run tests like this, I would do something like:
class UserControllerTest {
#InjectMocks
private UserController userController;
private MockMvc mockMvc;
#BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
mockMvc =
MockMvcBuilders.standaloneSetup(userController).build();
}
#Test
public void givenEmployees_whenGetEmployees_thenReturnJsonArray()
throws Exception {
User alex = new User();
List<UserResponse> allUsers = Arrays.asList(new
UserResponse(alex.getId(), alex.getInfo()));
RequestBuilder request = MockMvcRequestBuilders.get("/hello");
MvcResult result = mvc.perform(request).andReturn();
assertEquals(result.getResponse().getContentAsString(),
"hello");
}
}
I was using the wrong import. Changing to this fixed it
import static org.junit.Assert.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

Spring Cloud Contract not executing #Before

I am writing tests using Spring Cloud Contract.
In my configuration I am using for test an in memory DB that is created and destroyed at each test run.
In order to test successfully I need to put some data in the DB but it seems like the classic #Before annotation used in jUnit does not work (the code in it is never executed).
import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.Before;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.web.context.WebApplicationContext;
#ExtendWith(SpringExtension.class)
#SpringBootTest
public class BaseTestClass {
private static final Logger LOGGER = LoggerFactory.getLogger(BaseTestClass.class);
#Autowired
EntityRepository entityRepository;
#Autowired
private WebApplicationContext context;
#Before
public void init() {
// This code never runs
LOGGER.info("Init started");
MyEntity entity1 = new MyEntity();
entityRepository.save(entity1);
}
#BeforeEach
public void setup() {
RestAssuredMockMvc.webAppContextSetup(context);
}
}
What am I missing?
#Before belongs to JUnit4 and earlier while #BeforeEach belongs to JUnit5 as a replacement and clarification of #Before. If you are running with JUnit5, perhaps put all your initialization logic in #BeforeEach (or if it's a one-time init, in #BeforeAll)
I've found a solution that works.
I was adding the #TestInstance decorator incorrectly, here's my working solution:
import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.web.context.WebApplicationContext;
#ExtendWith(SpringExtension.class)
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class BaseTestClass {
private static final Logger LOGGER = LoggerFactory.getLogger(BaseTestClass.class);
#Autowired
EntityRepository entityRepository;
#Autowired
private WebApplicationContext context;
#BeforeAll
public void init() {
LOGGER.info("Init started");
MyEntity entity1 = new MyEntity();
entityRepository.save(entity1);
}
#BeforeEach
public void setup() {
RestAssuredMockMvc.webAppContextSetup(context);
}
}

Spring Boot Restcontroller as inner class in unit test (webmvctest)

Is it somehow possible to declare a RestController in a test context, preferably as a inner class of a spring boot test? I do need it for a specific test setup. I already did try following simple example as a POC:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.AutoConfigureWebClient;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
#ExtendWith(SpringExtension.class)
#WebMvcTest(ExampleTest.TestController.class)
#AutoConfigureMockMvc
#AutoConfigureWebClient
public class ExampleTest {
#Autowired
private MockMvc mockMvc;
#Test
public void exampleTest() throws Exception {
ResultActions resultActions = this.mockMvc
.perform(get("/test"));
resultActions
.andDo(print());
}
#RestController
public static class TestController {
#GetMapping("/test")
public String test() {
return "hello";
}
}
}
Testing the endpoint via MockMvc delivers 404 though. Am i missing something?
The problem is, TestController is not loaded to the application context. It could be solved by adding
#ContextConfiguration(classes= ExampleTest.TestController.class)
The test will look like:
#ExtendWith(SpringExtension.class)
#WebMvcTest(ExampleTest.TestController.class)
#ContextConfiguration(classes= ExampleTest.TestController.class)
#AutoConfigureMockMvc
#AutoConfigureWebClient
public class ExampleTest {
#Autowired
private MockMvc mockMvc;
#Test
public void exampleTest() throws Exception {
ResultActions resultActions = this.mockMvc
.perform(get("/test"));
resultActions
.andDo(print());
}
#RestController
public static class TestController {
#GetMapping("/test")
public String test() {
return "hello";
}
}
}
And the output:
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"5"]
Content type = text/plain;charset=UTF-8
Body = hello
Forwarded URL = null
Redirected URL = null
Cookies = []

Spring testing controller does not work

I have following class :
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import server.testing.WebTest;
public class CampaignControllerTest extends WebTest {
#Autowired
CampaignController campaignController;
private MockMvc mockMvc;
#Before
public void mySetup() throws Exception {
this.mockMvc = MockMvcBuilders.standaloneSetup(campaignController).build();
}
#Test
public void testStatus() throws Exception{
mockMvc.perform(get("/01/status")).andExpect((status().isOk()));
}
}
And I get following error : Failed tests: testStatus(cz.coffeeexperts.feedback.server.web.controller.CampaignControllerTest): Status expected:<200> but was:<404>
404 is (usually) thrown, if you type wrong address.
This is my CampaingController :
#Controller
#RequestMapping(value = "/api")
public class CampaignController {
#RequestMapping(value = "/01/status", method = RequestMethod.GET)
#ResponseBody
public ServerStatusJSON getStatus() {
return new ServerStatusJSON(activeCampaignService.getActiveCampaign().getIdCampaign());
}
}
This address I try to test works fine when I deploy this application on tomcat. There should not be problem inside that method, because in that case it returns 500 internal error, not 404.
Am I doing something wrong?
Try mockMvc.perform(get("/api/01/status")).andExpect((status().isOk()));

Spring MVC test with MockMvc

I'm trying to run a test for testing a Spring MVC controller. The test compile and runs, but my problem is that I got a PageNotFound warning:
WARN PageNotFound - No mapping found for HTTP request with URI [/] in DispatcherServlet with name ''
My really simple test as follows:
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
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.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration({
"classpath*:/WEB-INF/applicationContext.xml",
"classpath*:/WEB-INF/serviceContext.xml"
})
public class FrontPageControllerTest {
#Autowired
private WebApplicationContext ctx;
private MockMvc mockMvc;
#Before
public void init() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.ctx).build();
}
#Test
public void frontPageController() throws Exception {
this.mockMvc.perform(get("/"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(view().name("searchfrontpage"));
}
}
I'm 100% sure that my webapp maps to the frontpage at "/" and that the name on the view is "searchfrontpage".
Please help!
Another easier way to solve the issue is to change init to this :
mockMvc = MockMvcBuilders.standaloneSetup(new FrontPageController()).build();
My ContextConfiguration was wrong. Correct was:
#ContextConfiguration({
"file:src/main/webapp/WEB-INF/applicationContext.xml",
"file:src/main/webapp/WEB-INF/serviceContext.xml"
})
Now everything works fine.

Categories