i have created a basic CRUD api with spring boot.I have written test cases for the controller class,but i’m getting error when running the test. The code’s i tried is given Below
model
package com.example.crudrestapi.model; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Data @Entity @Builder @AllArgsConstructor @NoArgsConstructor public class Customer { @Id @GeneratedValue private Long id; private String name; private String address; private String phoneNumber; private String gstin; private float outstandingBalance; }
CrudController
public class CrudController { @Autowired CustomerRepo customerRepo; @PostMapping("/customers") public @ResponseBody Customer postCustomer(@RequestBody Customer customer) { return customerRepo.save(customer); } @PutMapping("customers/{customerId}") public ResponseEntity<Customer> updateCustomer(@RequestBody Customer newCustomer, @PathVariable Long customerId) { Optional<Customer> optionalCustomer = customerRepo.findById(customerId); if (optionalCustomer.isPresent()){ Customer c = optionalCustomer.get(); if (newCustomer.getName() != null) c.setName(newCustomer.getName()); if (newCustomer.getGstin() != null) c.setGstin(newCustomer.getGstin()); if (newCustomer.getPhoneNumber() != null) c.setPhoneNumber(newCustomer.getPhoneNumber()); if (newCustomer.getAddress() != null) c.setAddress(newCustomer.getAddress()); if (newCustomer.getOutstandingBalance() != 0.0f) c.setOutstandingBalance(newCustomer.getOutstandingBalance()); return new ResponseEntity<>(customerRepo.save(c), HttpStatus.OK); }else{ return new ResponseEntity<>(HttpStatus.NOT_FOUND); } } @DeleteMapping("customers/{customerId}") public String deleteCustomer(@PathVariable Long customerId) throws ResourceNotFoundException { return customerRepo.findById(customerId) .map(customer -> { customerRepo.delete(customer); return "Success"; }) .orElseThrow(() -> new ResourceNotFoundException()); } }
CrudControllerTest
package com.example.crudrestapi.controller; import com.example.crudrestapi.model.Customer; import com.example.crudrestapi.repository.CustomerRepo; 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.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import java.util.Arrays; import java.util.Optional; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.hasSize; import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @ExtendWith(SpringExtension.class) @WebMvcTest(CrudController.class) class CrudControllerTest { @Autowired MockMvc mockMvc; @MockBean CustomerRepo customerRepo; @Test void postCustomer() throws Exception { Customer customer = Customer.builder().name("name").address("address").build(); given(customerRepo.save(customer)); mockMvc.perform(post("/customers") .contentType(MediaType.APPLICATION_JSON) .content(customer.toString()) ) .andExpect(status().isOk()); } @Test void deleteCustomer() throws Exception { Customer customer = Customer.builder().name("name").address("address").build(); given(customerRepo.findById(Long.parseLong("1"))).willReturn(Optional.empty()); mockMvc.perform(delete("/customers/{customerId}", 1) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); } }
Error I’m Getting for POST api test
java.lang.AssertionError: Status expected:<200> but was:<400> Expected :200 Actual :400 <Click to see difference> at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:59) at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:122) at org.springframework.test.web.servlet.result.StatusResultMatchers.lambda$matcher$9(StatusResultMatchers.java:627) at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:196) at com.example.crudrestapi.controller.CrudControllerTest.postCustomer(CrudControllerTest.java:55) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:688) at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131) at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140) at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84) at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115) at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105) at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45) at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104) at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) at java.base/java.util.ArrayList.forEach(ArrayList.java:1541) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) at java.base/java.util.ArrayList.forEach(ArrayList.java:1541) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129) at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137) at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126) at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84) at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53) Suppressed: org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected here: -> at com.example.crudrestapi.controller.CrudControllerTest.postCustomer(CrudControllerTest.java:50) E.g. thenReturn() may be missing. Examples of correct stubbing: when(mock.isOk()).thenReturn(true); when(mock.isOk()).thenThrow(exception); doThrow(exception).when(mock).someVoidMethod(); Hints: 1. missing thenReturn() 2. you are trying to stub a final method, which is not supported 3. you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed at org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener.resetMocks(ResetMocksTestExecutionListener.java:82) at org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener.resetMocks(ResetMocksTestExecutionListener.java:69) at org.springframework.boot.test.mock.mockito.ResetMocksTestExecutionListener.afterTestMethod(ResetMocksTestExecutionListener.java:63) at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:441) at org.springframework.test.context.junit.jupiter.SpringExtension.afterEach(SpringExtension.java:205) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAfterEachCallbacks$11(TestMethodTestDescriptor.java:253) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$12(TestMethodTestDescriptor.java:269) at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$13(TestMethodTestDescriptor.java:269) at java.base/java.util.ArrayList.forEach(ArrayList.java:1541) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAllAfterMethodsOrCallbacks(TestMethodTestDescriptor.java:268) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAfterEachCallbacks(TestMethodTestDescriptor.java:252) at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137) ... 43 more 2020-12-27 18:23:51.851 INFO 10488 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor' Process finished with exit code -1
Delete Api test case Error
java.lang.AssertionError: Status expected:<200> but was:<404> Expected :200 Actual :404
I’m failing in the above test cases.I don’t know what is the issue.I’m Just a noob in testing environment .Any Suggestion would be a great help to me.
EDIT
Post api Error
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected here: -> at com.example.crudrestapi.controller.CrudControllerTest.postCustomer(CrudControllerTest.java:52) E.g. thenReturn() may be missing. Examples of correct stubbing: when(mock.isOk()).thenReturn(true); when(mock.isOk()).thenThrow(exception); doThrow(exception).when(mock).someVoidMethod(); Hints: 1. missing thenReturn() 2. you are trying to stub a final method, which is not supported 3. you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed
Advertisement
Answer
I think the problem is the test. In particular, the way that you send the information in the body because you send an Object but the MockMvc needs a String with the JSON format to simulate a real request from outside of the API.
The way to fix the problem is:
@Test void postCustomer() throws Exception { Customer customer = Customer.builder().name("name").address("address").build(); given(customerRepo.save(customer)); mockMvc.perform(post("/customers") .contentType(MediaType.APPLICATION_JSON) .content(asJsonString(customer))//Call to other method to transform an object to a JSON ) .andExpect(status().isOk()); } private String asJsonString(final Object obj) { try { return new ObjectMapper().writeValueAsString(obj); } catch (Exception e) { throw new RuntimeException(e); } }
The class ObjectMapper is from this package com.fasterxml.jackson.databind.ObjectMapper