How to test spring controller handler response - spring

I have spring controller handler. I have to test that handle by using Junit test case. I am new to Juint so not able to test Junit. I want to run this in eclipse.
spring handler:
#Controller
#RequestMapping("/core")
public class HelloController {
#RequestMapping(value = "/getEntityType", method = RequestMethod.GET)
public ResponseEntity<List<MyEnum >> getEntityType(HttpServletRequest
request, HttpServletResponse response) {
return new ResponseEntity<List<MyEnum >>(Arrays.asList(MyEnum.values()), HttpStatus.OK);
}
Enum Class:
public enum MyEnum {
FIRST, SECOND, THIRD;
}
TestCase:
#Test
public void testToFindEnumTypes() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "core/getEntityType");
MockHttpServletResponse response = new MockHttpServletResponse();
hello.Controller.getEntityType(request, response);
Assert.assertNotNull(getResponseJSON(response));
}
Please tell me how to Run Junit Test case for that handler. I am new to Junit testing.

From Eclipse, there should be a green run button that allows you to run JUnit tests.
Eclipse Help has this really good article explaining how to:
https://help.eclipse.org/neon/index.jsptopic=%2Forg.eclipse.jdt.doc.user%2FgettingStarted%2Fqs-junit.htm
Also, if running outside your Eclipse, and doing it in a maven build, you need to add junit dependency to your maven pom.xml file:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
Then run maven test command as follows:
mvn clean test
Also, there a few syntax errors in your posted code. It should be like something like this:
public class HelloControllerTest {
private HelloController helloController = new HelloController();
#Test
public void testToFindEnumTypes() throws Exception {
// setup
MockHttpServletRequest request = new MockHttpServletRequest("GET", "core/getEntityType");
MockHttpServletResponse response = new MockHttpServletResponse();
// execution
ResponseEntity actualResponse = helloController.getEntityType(request, response);
// verify
assertNotNull(actualResponse);
assertEquals(HttpStatus.OK, actualResponse.getStatusCode());
List<MyEnum> myEnumList = (List<MyEnum>) actualResponse.getBody();
assertTrue(myEnumList.contains(MyEnum.FIRST));
assertTrue(myEnumList.contains(MyEnum.SECOND));
assertTrue(myEnumList.contains(MyEnum.THIRD));
}
Ideally, you should also verify correctly all the return values like i done in the example above.

Related

Can not create mock of the final class, when Retryable is used

I have spring boot application with kotlin, and the thing is: I can't mock 3rd party final class only when #Retryable is used. Here is my project:
#Component
class RestClient {
fun getAllData() : List<String> = listOf("1")
}
#Service
class MyService(val restClient: RestClient) {
#Retryable(maxAttempts = 3)
fun makeRestCall() : List<String> {
return restClient.getAllData()
}
}
So I would like to test two cases:
when RestClient throws HttpClientErrorException.NotFound exception,
makeRestCall() should return null (that is not supported by
current implementation by that does not matter)
when makeRestCall() is invoked - I would like to check with mockito that it is really invoked (no sense, but why can't I do it? )
Here is my test:
#EnableRetry
#RunWith(SpringRunner::class)
class TTest {
#MockBean
lateinit var restClient: RestClient
#SpyBean
lateinit var myService: MyService
#Test
fun `should throw exception`() {
val notFoundException = mock<HttpClientErrorException.NotFound>()
whenever(restClient.getAllData()).thenThrow(notFoundException)
}
#Test
fun `method should be invoked`() {
myService.makeRestCall()
verify(myService).makeRestCall()
}
}
In order to mock final class org.springframework.web.client.HttpClientErrorException.NotFound, I've added mockito-inline as dependency
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
So, here is the problem:
when I run my tests with mockito-inline as dependency:
test should throw exception - passes
test method should be invoked - fails with exception :Argument passed to verify() is of type MyService$$EnhancerBySpringCGLIB$$222fb0be and is not a mock!
when I run my tests without mockito-inline as dependency:
test should throw exception - fails with exception: Mockito cannot mock/spy because : final class
test `method should be invoked - passes
when I run my tests without #EnableRetry - both tests passes, but I'm not able to test retry functionality
How can I deal with that?

Mockito when statement not triggering during Spring Boot REST Controller Test

I've written a typical three layer Spring Boot REST API and am building out the tests for it. The API itself works fine but I am running into issues getting the controller tests to work. The body that's being returned is empty because the object the controller layer is getting back is null. Here are the main dependencies in play.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
I've mocked out the service layer but the when statement in the test doesn't seem to be firing as I'd expect.
Here's the test itself:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
#AutoConfigureMockMvc
public class VehicleControllerTest {
#MockBean
VehicleServiceImpl vService;
#Mock
HttpServletRequest mockRequest;
#Mock
Principal mockPrincipal;
#Autowired
MockMvc mockMvc;
Vehicle vehicle1;
#BeforeEach
public void setUp() throws ItemNotFoundException {
vehicle1 = new Vehicle();
vehicle1.setVin("5YJ3E1EA5KF328931");
vehicle1.setColor("black");
vehicle1.setDisplayName("Black Car");
vehicle1.setId(1L);
}
#Test
#WithMockUser("USER")
public void findVehicleByIdSuccess() throws Exception {
//Given **I think the problem is here***
when(vService.findVehicleById(any(),any(),any())).thenReturn(vehicle1);
//When
this.mockMvc.perform(get("/vehicles/1")).andDo(print())
//Then
.andExpect(status().isOk());
}
}
Here's the corresponding controller method:
#Secured("ROLE_USER")
public class VehicleController {
#JsonView(VehicleView.summary.class)
#GetMapping("/vehicles/{id}")
public Vehicle findVehicleById(#PathVariable Long id, Principal principal,
HttpServletRequest request) throws ItemNotFoundException {
log.info("In controller " +LogFormat.urlLogFormat(request,principal.getName()));
return vehicleService.findVehicleById(id,principal, request);
}
Here's the MockHTTPServletResponse. It has a status of 200 but the body is empty
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
For reference here's the service method that I'm trying to Mock
#Override
public Vehicle findVehicleById(Long id, Principal principal, HttpServletRequest request) throws ItemNotFoundException {
Optional<Vehicle> vehicle = vehicleRepository.findByIdAndUserId(id,principal.getName());
if (vehicle.isPresent()){
return vehicle.get();
} else {
throw new ItemNotFoundException(id,"vehicle");
}
}
I've tried different versions of Springboot but that hasn't helped. I had started off using 2.2.4 but I figured I would try the 2.1.X train since it has been around longer. I can confirm the correct method in the controller is being called because of the log output I'm getting.
Try replacing the following line:
when(vService.findVehicleById(any(),any(),any())).thenReturn(vehicle1);
with this (explicitity provide the class in any()):
when(vService.findVehicleById(any(Long.class),any(Principal.class),any(HttpServletRequest.class))).thenReturn(vehicle1);
Ignore the following part, as #M. Deinum pointed out that #MockBean does inject the mock object so this is irrelevant.
You did mock your service object but you didn't inject it into your controller.
#InjectMocks
private VehicleController vehicleController = new VehicleController();
Initialize these mock objects using MockitoAnnotations.initMocks(this) and instead of autowiring MockMvc object try to pass your controller in it like this:
#BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(vehicleController).build();

Working of routing functions (reactive-webflux) with spring cloud contract

I am building a spring webflux project in which I have implemented Routing function as controllers with spring customer driven contract.
I am facing issue while the tests cases are getting executed and I haven't found any solution regarding this online anywhere.
My requirement is to execute the generated tests and loading the application context for n no. of tests.Below is the sample code:
==========Base class===========
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class GetBase extends SampleParentBase{
protected MockMvc mvc ;
#MockBean
private PersonService service;
#MockBean
private ServerRequest request;
#Before
public void setup() throws Exception {
mvc = MockMvcBuilders
.webAppContextSetup(context).build();
}
}
============groovy file==================
Contract.make {
description "."
request {
method GET()
urlPath('/person/1')
headers {
contentType(applicationJson())
header('''Accept''', applicationJson())
}
}
response {
headers {
contentType(applicationJson())
}
status 200
bodyMatchers {
jsonPath('$.name', byType())
jsonPath('$.age', byType())
jsonPath('$.pId', byType())
}
body ('''{
"name":"string",
"age":20,
"pId":"string"
}''')
}
}
=======================Router Configuration====================
#Configuration
public class RoutesConfiguration {
#Autowired
PersonRespository personRespository;
#Bean
RouterFunction<?> routes() {
return nest(path("/person"),
route(RequestPredicates.GET("/{id}"),
request -> ok().body(personRespository.findById(request.pathVariable("id")), Person.class))
.andRoute(method(HttpMethod.GET),
request -> ok().body(personRespository.findAll(), Person.class))
);
}
}
We've updated the snapshot documentation to contain information on how to work with Web Flux. You can check it out here https://cloud.spring.io/spring-cloud-contract/2.0.x/single/spring-cloud-contract.html#_working_with_web_flux and here you have a sample with Web Flux https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/master/producer_webflux . Let me copy the part of the documentation for your convenience
Spring Cloud Contract requires the usage of EXPLICIT mode in your generated tests to work with Web Flux.
Maven.
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<version>${spring-cloud-contract.version}</version>
<extensions>true</extensions>
<configuration>
<testMode>EXPLICIT</testMode>
</configuration>
</plugin>
Gradle.
contracts {
testMode = 'EXPLICIT'
}
The following example shows how to set up a base class and Rest Assured for Web Flux:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = BeerRestBase.Config.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = "server.port=0")
public abstract class BeerRestBase {
// your tests go here
// in this config class you define all controllers and mocked services
#Configuration
#EnableAutoConfiguration
static class Config {
#Bean
PersonCheckingService personCheckingService() {
return personToCheck -> personToCheck.age >= 20;
}
#Bean
ProducerController producerController() {
return new ProducerController(personCheckingService());
}
}
}

Spring Security + Spring-Boot Testing Controller

I'm trying to test the home controller
#RequestMapping("/")
#ResponseBody
String home() {
return "Hello World!";
}
I'm using spring security using as username "user" and test as password by default but #PreAuthorize is not working
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#PreAuthorize("hasRole('ADMIN')")
public class HomeControllerTest {
#Autowired
private TestRestTemplate restTemplate;
#Test
#WithMockUser(username = "user", password = "test", roles = "ADMIN")
public void home() throws Exception {
String body = this.restTemplate.getForObject("/", String.class);
assertThat(body).isEqualTo("Hello World!");
}
}
The result
Expected result:
<"[Hello World!]">
Actual result:
<"{"timestamp":1501100448216,"status":401,"error":"Unauthorized","message":"Full
authentication is required to access this resource","path":"/"}]">
Am I missing something?
Try to add the following to your test class:
#TestExecutionListeners(mergeMode = MergeMode.MERGE_WITH_DEFAULTS, listeners = {
WithSecurityContextTestExecutionListener.class
})
And the following dependency if you don't have it:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
Spring security require an extra listener that is not present in tests by default so you need to tell spring to add it by specifing the #TestExecutionListeners annotation in merge mode so it will merge the current listed listeners with the listeners you want to add - in this case WithSecurityContextTestExecutionListener

How to verify web responses when using Spring and test-mvc

A question about how to use test-mvc for unit testing.
I have a simple controller:
#Controller
#RequestMapping("/users")
public class UserController {
private UserService business;
#Autowired
public UserController(UserService bus)
{
business = bus;
}
#RequestMapping(value="{id}", method = RequestMethod.GET)
public #ResponseBody User getUserById(#PathVariable String id) throws ItemNotFoundException{
return business.GetUserById(id);
}
(( My idea is to keep the controllers so thin as possible.))
To test this controller I am trying to do something like this.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:mvc-dispatcher-servlet.xml"})
public class UserControllerTest extends ControllerTestBase {
UserService mockedService;
#Before
public void Setup()
{
MockitoAnnotations.initMocks( this );
mockedService = mock(UserService.class);
}
#Test
public void ReturnUserById() throws Exception{
User user = new User();
user.setName("Lasse");
stub(mockedService.GetUserById("lasse")).toReturn(user);
MockMvcBuilders.standaloneSetup(new UserController(mockedService)).build()
.perform(get("/users/lasse"))
.andExpect(status().isOk())
.andExpect(?????????????????????????????);
}
My intention is to check that proper json code is returned,,,,,,
I am not a pro,,, so I have not found a way to replace ??????????????????????? with code to do verify the returned string but I am certain that there must be a elegant way to do this
Can anyone fill me in?
//lg
content().string(containsString("some part of the string"))
assuming that you have this import:
import static org.springframework.test.web.server.result.MockMvcResultMatchers.*;
Update: Adding jsonPath also based on your comments:
You can add a dependency to json-path, the 1.0.M1 seems to depend on an much older version of json-path though:
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>0.5.5</version>
<scope>test</scope>
</dependency>
With this your test can look like this:
.andExpect(jsonPath("$.persons[0].first").value("firstName"));

Resources