In this answer, I was using REST-assured to test a post action of a file. The controller was:
#RestController
#RequestMapping("file-upload")
public class MyRESTController {
#Autowired
private AService aService;
#RequestMapping(method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
#ResponseStatus(HttpStatus.CREATED)
public void fileUpload(
#RequestParam(value = "file", required = true) final MultipartFile file,
#RequestParam(value = "something", required = true) final String something) {
aService.doSomethingOnDBWith(file, value);
}
}
The controller was tested as in this answer.
Now I have an exception:
#ResponseStatus(value=HttpStatus.NOT_FOUND)
public class XNotFoundException extends RuntimeException {
public XNotFoundException(final String message) {
super(message);
}
}
and I test the case when the service throws that exception as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MyApplication.class)
#WebAppConfiguration
#IntegrationTest({"server.port:0"})
public class ControllerTest{
{
System.setProperty("spring.profiles.active", "unit-test");
}
#Autowired
#Spy
AService aService;
#Autowired
#InjectMocks
MyRESTController controller;
#Value("${local.server.port}")
int port;
#Before public void setUp(){
RestAssured.port = port;
MockitoAnnotations.initMocks(this);
}
#Test
public void testFileUpload() throws Exception{
final File file = getFileFromResource(fileName);
doThrow(new XNotFoundException("Keep calm, is a test")).when(aService)
.doSomethingOnDBWith(any(MultipartFile.class), any(String.class));
given()
.multiPart("file", file)
.multiPart("something", ":(")
.when().post("/file-upload")
.then().(HttpStatus.NOT_FOUND.value());
}
}
But when I run the test I obtain:
java.lang.AssertionError: Expected status code <404> doesn't match actual status code <406>.
How can I solve this?
You may need to set the content-type header to "multipart/form-data". For example:
given()
.contentType(MediaType.MULTIPART_FORM_DATA_VALUE)
.multiPart("file", file)
.multiPart("something", ":(")
.when().post("/file-upload")
.then()...;
If that doesn't work you can try specify it for the individual multiparts:
given()
.multiPart("file", file, MediaType.MULTIPART_FORM_DATA_VALUE)
.multiPart("something", ":(", MediaType.MULTIPART_FORM_DATA_VALUE)
.when().post("/file-upload")
.then()...;
Related
If I try to test the post() endpoint, I see:
java.lang.AssertionError: No value at JSON path "$.firstName"
Caused by: java.lang.IllegalArgumentException: json can not be null or empty
But with the test for the get() all work fine.
And in the postTest() the result for status is correct.
Where is my mistaker?
Is it correct way to test the rest controller in this style?
#RunWith(MockitoJUnitRunner.Silent.class)
public class Temp {
private final Employee successfullyRegisteredEmployee = new Employee(2L, "Iven");
private final Employee employeeGetById = new Employee(2L, "Iven");
#Mock
private EmployeeServiceImpl serviceMock;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(new EmployeeControllerImpl( serviceMock))
.build();
}
#Test
public void getTest() throws Exception {
when(serviceMock.getEmployee(2L)).thenReturn(employeeGetById);
mockMvc.perform(get("/employee/get/2"))
.andExpect(status().is(200))
.andExpect(content().json(("{'firstName':'Iven'}")));
verify(serviceMock).getEmployee(2L);
}
#Test
public void postTest() throws Exception {
String json = "{\n" +
" \"firstName\": \"Iven\"\n"
"}";
when(serviceMock.register(employeeForRegister)).thenReturn(successfullyRegisteredEmployee);
mockMvc.perform( MockMvcRequestBuilders
.post("/employee/register")
.content(json)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is(201))
.andExpect(jsonPath("$.firstName", Matchers.is("Iven")));
}
}
#RestController
#RequestMapping("/employee")
public class EmployeeControllerImpl implements EmployeeController {
private final EmployeeService service;
public EmployeeControllerImpl(EmployeeService service) {
this.service = service;
}
#PostMapping(path = "/register",
consumes = "application/json",
produces = "application/json"
)
public ResponseEntity<Employee> registerEmployee(#Valid #RequestBody Employee employee) {
Employee registeredEmployee = service.register(employee);
return ResponseEntity.status(201).body(registeredEmployee);
}
}
Seems like problem could be with when(serviceMock.register(employeeForRegister)).thenReturn(successfullyRegisteredEmployee);.
Did you try to have breakpoint on return ResponseEntity.status(201).body(registeredEmployee); to check if registeredEmployee is actually filled?
If it's empty then try replacing mock with when(serviceMock.register(any())).thenReturn(successfullyRegisteredEmployee); and if it works that means either equals() method is not overridden for Employee or comparison just fails.
I want to create JUnit test for Rest api and generate api doc. I want to test this code:
Rest controller
#RestController
#RequestMapping("/transactions")
public class PaymentTransactionsController {
#Autowired
private PaymentTransactionRepository transactionRepository;
#GetMapping("{id}")
public ResponseEntity<?> get(#PathVariable String id) {
return transactionRepository
.findById(Integer.parseInt(id))
.map(mapper::toDTO)
.map(ResponseEntity::ok)
.orElseGet(() -> notFound().build());
}
}
Repository interface
public interface PaymentTransactionRepository extends CrudRepository<PaymentTransactions, Integer>, JpaSpecificationExecutor<PaymentTransactions> {
Optional<PaymentTransactions> findById(Integer id);
}
I tried to implement this JUnit5 test with mockito:
#ExtendWith({ RestDocumentationExtension.class, SpringExtension.class })
#SpringBootTest(classes = PaymentTransactionsController.class)
#WebAppConfiguration
public class PaymentTransactionRepositoryIntegrationTest {
.....
private MockMvc mockMvc;
#MockBean
private PaymentTransactionRepository transactionRepository;
#BeforeEach
void setUp(WebApplicationContext webApplicationContext,
RestDocumentationContextProvider restDocumentation) {
PaymentTransactions obj = new PaymentTransactions(1);
Optional<PaymentTransactions> optional = Optional.of(obj);
PaymentTransactionRepository processor = Mockito.mock(PaymentTransactionRepository.class);
Mockito.when(processor.findById(Integer.parseInt("1"))).thenReturn(optional);
this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.apply(documentationConfiguration(restDocumentation))
.alwaysDo(document("{method-name}", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint())))
.build();
}
#Test
public void testNotNull() {
assertNotNull(target);
}
#Test
public void testFindByIdFound() {
Optional<PaymentTransactions> res = target.findById(Integer.parseInt("1"));
// assertTrue(res.isPresent());
}
#Test
public void indexExample() throws Exception {
this.mockMvc.perform(get("/transactions").param("id", "1"))
.andExpect(status().isOk())
.andExpect(content().contentType("application/xml;charset=UTF-8"))
.andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")),
responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`"))));
}
}
I get error:
java.lang.AssertionError: Status expected:<200> but was:<404>
What his the proper way to to make GET request to the above code?
Probably I need to add response OK when message is send back?
hi in my case i needed #MockBean of controller and all services that is was autowireing ;)
Instead of #PostMapping and #GetMapping which caused same problem while #RequestMapping in controller helped
It's a path variable, so instead of using param value, please use path variable.
For MvcResult import, you can import org.springframework.test.web.servlet
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
...
given(target.findById(anyInt())).willReturn(Optional.of(new PaymentTransactions(1))).andReturn();
MvcResult result = this.mockMvc.perform(get("/transactions/1")
.accept("application/xml;charset=UTF-8")).andReturn();
String content = result.getResponse().getContentAsString();
this.mockMvc.perform(get("/transactions/1")
.accept("application/xml;charset=UTF-8"))
.andExpect(status().isOk())
.andDo(document("index-example", preprocessRequest(prettyPrint()), preprocessResponse(prettyPrint()), links(linkWithRel("crud").description("The CRUD resource")), responseFields(subsectionWithPath("_links").description("Links to other resources")),
responseHeaders(headerWithName("Content-Type").description("The Content-Type of the payload, e.g. `application/hal+json`"))));
Can you try this..
public class PaymentTransactionsControllerTest {
private MockMvc mvc;
#InjectMocks
PaymentTransactionsController paymentTransactionsController;
#MockBean
private PaymentTransactionRepository processor;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(paymentTransactionsController).build();
}
#Test
public void indexExample() throws Exception {
PaymentTransactions obj = new PaymentTransactions(1);
Optional<PaymentTransactions> optional = Optional.of(obj);
Mockito.when(processor.findById(Integer.parseInt("1"))).thenReturn(optional);
MvcResult result = mvc.perform(MockMvcRequestBuilders.get("/transactions/{id}", 1))
.andDo(print())
.andExpect(status().isOk())
.andReturn();
Assert.assertNotNull(result.getResponse().getContentAsString());
}
}
I am creating my first unit test, and just wanted to create something pretty simple based on one of the Spring tutorials.
Here is the error I am getting:
java.lang.AssertionError: Response content
Expected: (null or an empty string)
but: was "Debug"
My Controller:
#RestController
#RequestMapping(value = "/person")
public class PersonController {
#Autowired
protected PersonService personService;
#RequestMapping(value = "/lastName", produces = "application/json")
public String lastName(#RequestParam(value = "cid") String cid)
{
return personService.findByCId(cid).getLastName();
}
My Test:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class MvcLastNameTest {
#Autowired
private MockMvc mockMvc;
#Test
public void shouldReturnNonNullString() throws Exception {
this.mockMvc.perform(get("/person/lastName?cid=123456")).andDo(print()).andExpect(status().isOk())
.andExpect(content().string(isEmptyOrNullString()));
}
}
in your test your are expecting EmptyOrNullString, but your controller produces a lastName
change your expectation:
.andExpect(content().string("Debug")); // or any other valid lastName
I use Spring MVC and Spring boot to write a Restful service. This code works fine through postman.While when I do the unit test for the controller to accept a post request, the mocked myService will always initialize itself instead of return a mocked value defined by when...thenReturn... I use verify(MyService,times(1)).executeRule(any(MyRule.class)); and it shows the mock is not used.
I also tried to use standaloneSetup for mockMoc, but it complains it can't find the mapping for the path "/api/rule".
Could anybody help to figure out the problem?
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class MyControllerTest {
#Mock
private MyService myService;
#InjectMocks
private MyController myRulesController;
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void controllerTest() throws Exception{
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
Long userId=(long)12345;
MyRule happyRule = MyRule.createHappyRule(......);
List<myEvent> mockEvents=new ArrayList<myEvent>();
myEvents.add(new MyEvent(......));
when(myService.executeRule(any(MyRule.class))).thenReturn(mockEvents);
String requestBody = ow.writeValueAsString(happyRule);
MvcResult result = mockMvc.perform(post("/api/rule").contentType(MediaType.APPLICATION_JSON)
.content(requestBody))
.andExpect(status().isOk())
.andExpect(
content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
verify(MyService,times(1)).executeRule(any(MyRule.class));
String jsonString = result.getResponse().getContentAsString();
}
}
Below is my controller class, where MyService is a interface. And I have implemented this interface.
#RestController
#RequestMapping("/api/rule")
public class MyController {
#Autowired
private MyService myService;
#RequestMapping(method = RequestMethod.POST,consumes = "application/json",produces = "application/json")
public List<MyEvent> eventsForRule(#RequestBody MyRule myRule) {
return myService.executeRule(myRule);
}
}
Is api your context root of the application? If so remove the context root from the request URI and test. Passing the context root will throw a 404. If you intend to pass the context root then please refer the below test case. Hope this helps.
#RunWith(MockitoJUnitRunner.class)
public class MyControllerTest {
#InjectMocks
private MyController myRulesController;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = standaloneSetup(myRulesController).build();
}
#Test
public void controllerTest() throws Exception{
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
MyController.User user = new MyController.User("test-user");
ow.writeValueAsString(user);
MvcResult result = mockMvc.perform(post("/api/rule").contentType(MediaType.APPLICATION_JSON).contextPath("/api")
.content(ow.writeValueAsString(user)))
.andExpect(status().isOk())
.andExpect(
content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
}
}
Below is the controller
/**
* Created by schinta6 on 4/26/16.
*/
#RestController
#RequestMapping("/api/rule")
public class MyController {
#RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
public User eventsForRule(#RequestBody User payload) {
return new User("Test-user");
}
public static class User {
private String name;
public User(String name){
this.name = name;
}
}
}
I am writing a test for controller using spring test mvc framework. I am trying to test a post request and it produces JSON. The actual code is running but test is failing.
I an getting the error Status expected 200 but getting 415 which means unsupported media type. i check all examples on net and it seems my implementation is correct. please help me out.
MyTestcase TestStringPost() is running successfully but TestJSONPost is failing.
I am using Spring 3.2
My Controller
#Controller
public class HomeController {
#RequestMapping(value = "/v1/checkstringvalue", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody void testStringPost(#RequestBody String value) {
logger.info("Welcome home! The client locale is {}.");
}
#RequestMapping(value = "/v1/checkjsonvalue", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody String testJSONPost(#RequestBody Map<String, String> userMap) {
System.out.println("Inside test jsonpost controller");
logger.info("Welcome home! The client locale is {}.");
return "Success";
}
}
This is my Test Controller
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#WebAppConfiguration
public class HomeControllerTest {
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
private static final String PROVIDER_A = "PROVIDER_A";
public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(
MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
#Configuration
public static class TestConfiguration {
#Bean
public HomeController simpleController() {
return new HomeController();
}
}
#Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
#Test
public void testStringPost() throws Exception {
final String createJson = "hello";
ResultActions resultActions = mockMvc.perform(post(
"/v1/checkstringvalue").contentType(MediaType.TEXT_PLAIN)
.content(createJson));
resultActions.andDo(print());
resultActions.andExpect(status().isOk());
}
#Test
public void testjsonPost() throws Exception {
System.out.println("Inside testjsonpost");
final String createJson = "{\"name\":\"hello\",\"email\":\"hello#example.com\"}";
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode userJson = objectMapper.createObjectNode();
userJson.put("name", "tarun");
userJson.put("email", "tarun#gmail.com");
ResultActions resultActions = mockMvc
.perform(post("/v1/checkjsonvalue")
.contentType(APPLICATION_JSON_UTF8)
.accept(APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsBytes(userJson)));
resultActions.andDo(print());
resultActions.andExpect(status().isOk());
}
}
Ok, so having the
perform(post("/myapi").contentType(MediaType.APPLICATION_JSON).content("{\"mykey\":\"myvalue\"}"))
is important.
BUT also check your controller: if it is missing any of these annotations, it won't work:
#EnableWebMvc
#Controller
public class MyController {
#RequestMapping(value="/myapi", method=RequestMethod.POST)
public void postOnApi(#RequestBody MyWidget myWidget) {
}
}
The #EnableWebMvc #Controller and #RequestBody are all needed (in my experimenting) to remove the 415 status code error.
Your test code:
ResultActions resultActions = mockMvc
.perform(post("/v1/checkjsonvalue")
.contentType(APPLICATION_JSON_UTF8)
.accept(APPLICATION_JSON_UTF8)
.content(objectMapper.writeValueAsBytes(userJson)));
Seems to add the contentType() header, but your source code does not have a consumes attribute in the #RequestMapping
#RequestMapping(value = "/v1/checkjsonvalue", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody String testJSONPost(#RequestBody Map<String, String> userMap) {
System.out.println("Inside test jsonpost controller");
logger.info("Welcome home! The client locale is {}.");
return "Success";
}
I think that if you take out the contentType() in your test case or add a consumes in the source code then it might work.
if you are using xml based config for your spring mvc project make sure that you have put #EnableWebMvc on your controller.