Using Spring MVC Test to unit test multipart POST request - spring

I have the following request handler for saving autos. I have verified that this works when I use e.g. cURL. Now I want to unit test the method with Spring MVC Test. I have tried to use the fileUploader, but I am not managing to get it working. Nor do I manage to add the JSON part.
How would I unit test this method with Spring MVC Test? I am not able to find any examples on this.
#RequestMapping(value = "autos", method = RequestMethod.POST)
public ResponseEntity saveAuto(
#RequestPart(value = "data") autoResource,
#RequestParam(value = "files[]", required = false) List<MultipartFile> files) {
// ...
}
I want to uplod a JSON representation for my auto + one or more files.
I will add 100 in bounty to the correct answer!

Since MockMvcRequestBuilders#fileUpload is deprecated, you'll want to use MockMvcRequestBuilders#multipart(String, Object...) which returns a MockMultipartHttpServletRequestBuilder. Then chain a bunch of file(MockMultipartFile) calls.
Here's a working example. Given a #Controller
#Controller
public class NewController {
#RequestMapping(value = "/upload", method = RequestMethod.POST)
#ResponseBody
public String saveAuto(
#RequestPart(value = "json") JsonPojo pojo,
#RequestParam(value = "some-random") String random,
#RequestParam(value = "data", required = false) List<MultipartFile> files) {
System.out.println(random);
System.out.println(pojo.getJson());
for (MultipartFile file : files) {
System.out.println(file.getOriginalFilename());
}
return "success";
}
static class JsonPojo {
private String json;
public String getJson() {
return json;
}
public void setJson(String json) {
this.json = json;
}
}
}
and a unit test
#WebAppConfiguration
#ContextConfiguration(classes = WebConfig.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class Example {
#Autowired
private WebApplicationContext webApplicationContext;
#Test
public void test() throws Exception {
MockMultipartFile firstFile = new MockMultipartFile("data", "filename.txt", "text/plain", "some xml".getBytes());
MockMultipartFile secondFile = new MockMultipartFile("data", "other-file-name.data", "text/plain", "some other type".getBytes());
MockMultipartFile jsonFile = new MockMultipartFile("json", "", "application/json", "{\"json\": \"someValue\"}".getBytes());
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
mockMvc.perform(MockMvcRequestBuilders.multipart("/upload")
.file(firstFile)
.file(secondFile)
.file(jsonFile)
.param("some-random", "4"))
.andExpect(status().is(200))
.andExpect(content().string("success"));
}
}
And the #Configuration class
#Configuration
#ComponentScan({ "test.controllers" })
#EnableWebMvc
public class WebConfig extends WebMvcConfigurationSupport {
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
return multipartResolver;
}
}
The test should pass and give you output of
4 // from param
someValue // from json file
filename.txt // from first file
other-file-name.data // from second file
The thing to note is that you are sending the JSON just like any other multipart file, except with a different content type.

The method MockMvcRequestBuilders.fileUpload is deprecated use MockMvcRequestBuilders.multipart instead.
This is an example:
import static org.hamcrest.CoreMatchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
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.Mockito;
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.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.multipart.MultipartFile;
/**
* Unit test New Controller.
*
*/
#RunWith(SpringRunner.class)
#WebMvcTest(NewController.class)
public class NewControllerTest {
private MockMvc mockMvc;
#Autowired
WebApplicationContext wContext;
#MockBean
private NewController newController;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wContext)
.alwaysDo(MockMvcResultHandlers.print())
.build();
}
#Test
public void test() throws Exception {
// Mock Request
MockMultipartFile jsonFile = new MockMultipartFile("test.json", "", "application/json", "{\"key1\": \"value1\"}".getBytes());
// Mock Response
NewControllerResponseDto response = new NewControllerDto();
Mockito.when(newController.postV1(Mockito.any(Integer.class), Mockito.any(MultipartFile.class))).thenReturn(response);
mockMvc.perform(MockMvcRequestBuilders.multipart("/fileUpload")
.file("file", jsonFile.getBytes())
.characterEncoding("UTF-8"))
.andExpect(status().isOk());
}
}

Have a look at this example taken from the spring MVC showcase, this is the link to the source code:
#RunWith(SpringJUnit4ClassRunner.class)
public class FileUploadControllerTests extends AbstractContextControllerTests {
#Test
public void readString() throws Exception {
MockMultipartFile file = new MockMultipartFile("file", "orig", null, "bar".getBytes());
webAppContextSetup(this.wac).build()
.perform(fileUpload("/fileupload").file(file))
.andExpect(model().attribute("message", "File 'orig' uploaded successfully"));
}
}

Here's what worked for me, here I'm attaching a file to my EmailController under test. Also take a look at the postman screenshot on how I'm posting the data.
#WebAppConfiguration
#RunWith(SpringRunner.class)
#SpringBootTest(
classes = EmailControllerBootApplication.class
)
public class SendEmailTest {
#Autowired
private WebApplicationContext webApplicationContext;
#Test
public void testSend() throws Exception{
String jsonStr = "{\"to\": [\"email.address#domain.com\"],\"subject\": "
+ "\"CDM - Spring Boot email service with attachment\","
+ "\"body\": \"Email body will contain test results, with screenshot\"}";
Resource fileResource = new ClassPathResource(
"screen-shots/HomePage-attachment.png");
assertNotNull(fileResource);
MockMultipartFile firstFile = new MockMultipartFile(
"attachments",fileResource.getFilename(),
MediaType.MULTIPART_FORM_DATA_VALUE,
fileResource.getInputStream());
assertNotNull(firstFile);
MockMvc mockMvc = MockMvcBuilders.
webAppContextSetup(webApplicationContext).build();
mockMvc.perform(MockMvcRequestBuilders
.multipart("/api/v1/email/send")
.file(firstFile)
.param("data", jsonStr))
.andExpect(status().is(200));
}
}

If you are using Spring4/SpringBoot 1.x, then it's worth mentioning that you can add "text" (json) parts as well . This can be done via MockMvcRequestBuilders.fileUpload().file(MockMultipartFile file) (which is needed as method .multipart() is not available in this version):
#Test
public void test() throws Exception {
mockMvc.perform(
MockMvcRequestBuilders.fileUpload("/files")
// file-part
.file(makeMultipartFile( "file-part" "some/path/to/file.bin", "application/octet-stream"))
// text part
.file(makeMultipartTextPart("json-part", "{ \"foo\" : \"bar\" }", "application/json"))
.andExpect(status().isOk())));
}
private MockMultipartFile(String requestPartName, String filename,
String contentType, String pathOnClassPath) {
return new MockMultipartFile(requestPartName, filename,
contentType, readResourceFile(pathOnClasspath);
}
// make text-part using MockMultipartFile
private MockMultipartFile makeMultipartTextPart(String requestPartName,
String value, String contentType) throws Exception {
return new MockMultipartFile(requestPartName, "", contentType,
value.getBytes(Charset.forName("UTF-8")));
}
private byte[] readResourceFile(String pathOnClassPath) throws Exception {
return Files.readAllBytes(Paths.get(Thread.currentThread().getContextClassLoader()
.getResource(pathOnClassPath).toUri()));
}
}

Related

Sprint boot - Auto configure to call a REST service on startup

I have a requirement to create an auto-configuration for service call on spring-boot startup.
i.e., During spring-boot startup, the below service has to be called.
#PostMapping(path = "/addProduct", produces = "application/json", consumes = "application/json")
public #ResponseBody String addProduct(#RequestBody String productStr) {
..<My code>..
}
The add product requires an input like:
{
"product":"test",
"price":"10"
}
This will internally call a database service.
During startup, the json input provided in the console should be fed to this service.
I have no idea on how to achieve this. Verified a couple of Spring documentation. But those does'nt suit the requirement.
Kindly help in explaining a way or providing a right documentation to achieve this.
One way to do this is by implementing ApplicationRunner like this :
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
#Component
public class ApplicationInitializer implements ApplicationRunner {
private ProductController productController;
public ApplicationInitializer(ProductController productController) {
this.productController = productController;
}
#Override
public void run(ApplicationArguments args) throws Exception {
String productArg = args.getOptionValues("product").get(0); // Assume that you will have only one product argument
ObjectMapper mapper = new ObjectMapper();
Product product = mapper.readValue(productArg, Product.class);
String response = productController.add(product);
System.out.println(response);
}
}
The run method will be invoked at startup with arguments passed in the command line like this : java -jar yourApp.jar --product="{\"name\":\"test\", \"price\":\"15\"}".
And you need a class to map the json to an object like this :
public class Product {
private String name;
private int price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
You can also call your Controller using the RestTemplate (or WebClient) if needed :
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
#Component
public class ApplicationInitializer implements ApplicationRunner {
#Override
public void run(ApplicationArguments args) throws Exception {
String productArg = args.getOptionValues("product").get(0); // Assume that you will have only one product argument
ObjectMapper mapper = new ObjectMapper();
Product product = mapper.readValue(productArg, Product.class);
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.postForObject("http://localhost:8080/products", product, String.class);
System.out.println(response);
}
}
Such requirement can be achieved by using an init() method annotated with #PostConstruct in a bean.
e.g.
#Component
public class Foo {
#PostConstruct
public void init() {
//Call your service
}
}

When using MockMvc to test the controller, a parameter passing error occurred

I am using MockMvc to test the controller. Regarding parameter import, I encountered a type mismatch problem. I tried all the json styles.But nothing works
This is my controller class::
package app.dnatask.controller;
import ......;
#Slf4j
#RestController
#RequestMapping(value = "/API/scanresultconfigure")
public class ScanResultConfigureController extends BaseController {
#RequestMapping(value = "/queryScanResultList/{taskId}/{externalname}", method = RequestMethod.POST)
public IBaseResult queryscanResultList(final HttpServletRequest request, #PathVariable final String taskId, #PathVariable final String externalname, #RequestBody Map map) throws Exception {
return runController(new IControllRunner() {
public void run(IOutResult or, CheckResult cr) throws Exception {
......
}
}
}
}
This is my test class::
package app.dnatask.controller;
import ......
#WebAppConfiguration
#ContextConfiguration(classes = {ScanResultConfigureController.class})
#ComponentScan(
includeFilters = {
#ComponentScan.Filter(type = FilterType.CUSTOM,
value = {ScanResultConfigureController.class})
},
useDefaultFilters = false,
lazyInit = true
)
public class ScanResultConfigureControllerTest extends AbstractTestNGSpringContextTests {
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
#BeforeMethod
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).dispatchOptions(true).build();
System.out.println("UT starting.............");
}
#AfterMethod
public void am() {
System.out.println("UT ending.............");
}
#Test
public void testQueryscanResultList() throws Exception {
Map<String, String> testMap = new HashMap<>();
testMap.put("key1", "value1");
testMap.put("key2", "value2");
String requestJson = JSONObject.toJSONString(testMap);
mockMvc.perform(
post("/API/scanresultconfigure/queryScanResultList/001/abc")
.contentType(MediaType.APPLICATION_JSON)
.param("map", requestJson)
)
.andExpect(status().isOk())
.andDo(print());
}
}
Error message::
org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json' not supported
java.lang.AssertionError: Status expected:<200> but was:<415>
This is a project implemented by springmvc framework, I use TestNG for unit testing.
Regarding my problem, the solution is as follows::
MvcResult mvcResult = mockMvc.perform(
post("/API/scanresultconfigure/queryScanResultList/{taskId}/{externalname}", "123", "abc")
.contentType(MediaType.APPLICATION_JSON)
.content(requestJson)
)
.andExpect(status().isOk())
.andDo(print())
.andReturn();

Is there a way to automatically propagate an incoming HTTP header in a JAX-RS request to an outgoing JAX-RS request?

I'm looking for the proper way—in a Jersey application—to read a header from an incoming request and automatically install it in any outgoing requests that might be made by a JAX-RS client that my application is using.
Ideally I'd like to do this without polluting any of my classes' inner logic at all, so via various filters and interceptors.
For simple use cases, I can do this: I have a ClientRequestFilter implementation that I register on my ClientBuilder, and that filter implementation has:
#Context
private HttpHeaders headers;
...which is a context-sensitive proxy (by definition), so in its filter method it can refer to headers that were present on the inbound request that's driving all this, and install them on the outgoing request. For straightforward cases, this appears to work OK.
However, this fails in the case of asynchronicity: if I use the JAX-RS asynchronous client APIs to spawn a bunch of GETs, the filter is still invoked, but can no longer invoke methods on that headers instance variable; Jersey complains that as far as it knows we're no longer in request scope. This makes sense if request scope is defined to be per-thread: the spawned GETs are running in some Jersey-managed thread pool somewhere, not on the same thread as the one with which the headers proxy is associated, so that proxy throws IllegalStateExceptions all over the place when my filter tries to talk to it.
I feel like there's some combination of ContainerRequestFilter and ClientRequestFilter that should be able to get the job done even in asynchronous cases, but I'm not seeing it.
What I would do is make a WebTarget injectable that is preconfigured with a ClientRequestFilter to add the headers. It's better to configure the WebTarget this way, as opposed to the Client, since the Client is an expensive object to create.
We can make the WebTarget injectable using a custom annotation and an InjectionResolver. In the InjectionResolver, we can get the ContainerRequest and get the headers from that, which we will pass to the ClientRequestFilter.
Here it is in action
Create the custom annotation
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface WithHeadersTarget {
String baseUri();
String[] headerNames() default {};
}
Make the InjectionResolver with the custom ClientRequestFilter
private static class WithHeadersTargetInjectionResolver
implements InjectionResolver<WithHeadersTarget> {
private final Provider<ContainerRequest> requestProvider;
private final Client client;
#Inject
public WithHeadersTargetInjectionResolver(Provider<ContainerRequest> requestProvider) {
this.requestProvider = requestProvider;
this.client = ClientBuilder.newClient();
}
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
if (injectee.getRequiredType() == WebTarget.class
&& injectee.getParent().isAnnotationPresent(WithHeadersTarget.class)) {
WithHeadersTarget anno = injectee.getParent().getAnnotation(WithHeadersTarget.class);
String uri = anno.baseUri();
String[] headersNames = anno.headerNames();
MultivaluedMap<String, String> requestHeaders = requestProvider.get().getRequestHeaders();
return client.target(uri)
.register(new HeadersFilter(requestHeaders, headersNames));
}
return null;
}
#Override
public boolean isConstructorParameterIndicator() {
return false;
}
#Override
public boolean isMethodParameterIndicator() {
return false;
}
private class HeadersFilter implements ClientRequestFilter {
private final MultivaluedMap<String, String> headers;
private final String[] headerNames;
private HeadersFilter(MultivaluedMap<String, String> headers, String[] headerNames) {
this.headers = headers;
this.headerNames = headerNames;
}
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
// if headers names is empty, add all headers
if (this.headerNames.length == 0) {
for (Map.Entry<String, List<String>> entry: this.headers.entrySet()) {
requestContext.getHeaders().put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
// else just add the headers from the annotation
} else {
for (String header: this.headerNames) {
requestContext.getHeaders().put(header, new ArrayList<>(this.headers.get(header)));
}
}
}
}
}
One thing about this implementation is that it checks for an empty headerNames in the #WithHeadersTarget annotation. If it is empty, then we just forward all headers. If the user specifies some header names, then it will only forward those
Register the InjectionResolver
new ResourceConfig()
.register(new AbstractBinder() {
#Override
protected void configure() {
bind(WithHeadersTargetInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<WithHeadersTarget>>() {
}).in(Singleton.class);
}
})
Use it
#Path("test")
public static class TestResource {
#WithHeadersTarget(
baseUri = BASE_URI
headerNames = {TEST_HEADER_NAME})
private WebTarget target;
#GET
public String get() {
return target.path("client").request().get(String.class);
}
}
In this example if, the headerNames is left out, then it will default to an empty array, which will cause all the request headers to be forwarded.
Complete test using Jersey Test Framework
import org.glassfish.hk2.api.Injectee;
import org.glassfish.hk2.api.InjectionResolver;
import org.glassfish.hk2.api.ServiceHandle;
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.filter.LoggingFilter;
import org.glassfish.jersey.server.ContainerRequest;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import static org.assertj.core.api.Assertions.assertThat;
public class ForwardHeadersTest extends JerseyTest {
private static final String BASE_URI = "http://localhost:8000";
private static final String TEST_HEADER_NAME = "X-Test-Header";
#Target({ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface WithHeadersTarget {
String baseUri();
String[] headerNames() default {};
}
#Path("test")
public static class TestResource {
#WithHeadersTarget(
baseUri = BASE_URI
)
private WebTarget target;
#GET
public String get() {
return target.path("client").request().get(String.class);
}
}
#Path("client")
public static class ClientResource {
#GET
public String getReversedHeader(#HeaderParam(TEST_HEADER_NAME) String header) {
System.out.println(header);
return new StringBuilder(header).reverse().toString();
}
}
private static class WithHeadersTargetInjectionResolver
implements InjectionResolver<WithHeadersTarget> {
private final Provider<ContainerRequest> requestProvider;
private final Client client;
#Inject
public WithHeadersTargetInjectionResolver(Provider<ContainerRequest> requestProvider) {
this.requestProvider = requestProvider;
this.client = ClientBuilder.newClient();
}
#Override
public Object resolve(Injectee injectee, ServiceHandle<?> handle) {
if (injectee.getRequiredType() == WebTarget.class
&& injectee.getParent().isAnnotationPresent(WithHeadersTarget.class)) {
WithHeadersTarget anno = injectee.getParent().getAnnotation(WithHeadersTarget.class);
String uri = anno.baseUri();
String[] headersNames = anno.headerNames();
MultivaluedMap<String, String> requestHeaders = requestProvider.get().getRequestHeaders();
return client.target(uri)
.register(new HeadersFilter(requestHeaders, headersNames));
}
return null;
}
#Override
public boolean isConstructorParameterIndicator() {
return false;
}
#Override
public boolean isMethodParameterIndicator() {
return false;
}
private class HeadersFilter implements ClientRequestFilter {
private final MultivaluedMap<String, String> headers;
private final String[] headerNames;
private HeadersFilter(MultivaluedMap<String, String> headers, String[] headerNames) {
this.headers = headers;
this.headerNames = headerNames;
}
#Override
public void filter(ClientRequestContext requestContext) throws IOException {
// if headers names is empty, add all headers
if (this.headerNames.length == 0) {
for (Map.Entry<String, List<String>> entry: this.headers.entrySet()) {
requestContext.getHeaders().put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
// else just add the headers from the annotation
} else {
for (String header: this.headerNames) {
requestContext.getHeaders().put(header, new ArrayList<>(this.headers.get(header)));
}
}
}
}
}
#Override
public ResourceConfig configure() {
return new ResourceConfig()
.register(TestResource.class)
.register(ClientResource.class)
.register(new AbstractBinder() {
#Override
protected void configure() {
bind(WithHeadersTargetInjectionResolver.class)
.to(new TypeLiteral<InjectionResolver<WithHeadersTarget>>() {
}).in(Singleton.class);
}
})
.register(new LoggingFilter(Logger.getAnonymousLogger(), true))
.register(new ExceptionMapper<Throwable>() {
#Override
public Response toResponse(Throwable t) {
t.printStackTrace();
return Response.serverError().entity(t.getMessage()).build();
}
});
}
#Override
public URI getBaseUri() {
return URI.create(BASE_URI);
}
#Test
public void testIt() {
final String response = target("test")
.request()
.header(TEST_HEADER_NAME, "HelloWorld")
.get(String.class);
assertThat(response).isEqualTo("dlroWolleH");
}
}

How to execute junit test case sequentially

I am writing integration test case which is used to create and update a data
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MyApplication.class, webEnvironment =
SpringBootTest.WebEnvironment.DEFINED_PORT)
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class MyIntegrationTest {
private String baseUrl="http://192.168.6.177/api/v1/";
#Autowired
TestRestTemplate restTemplate;
Long createdId; // trying to set ID which is coming after test1_AddData
#Test
public void test1_AddData() throws Exception {
ABC abc = new ABC("Name");
HttpEntity<ABC> requestBodyData = new HttpEntity<>(ABC);
ParameterizedTypeReference<RestTemplateResponseEnvelope<ABC>> typeReference =
new ParameterizedTypeReference<RestTemplateResponseEnvelope<ABC>>() {
};
ResponseEntity<RestTemplateResponseEnvelope<ABC>> response = restTemplate.exchange(
baseUrl + "/presenceType",
HttpMethod.POST, requestBodyData, typeReference);
Assert.assertTrue(HttpStatus.CREATED.equals(response.getStatusCode()));
createdId = response.getBody().getData().getId();
}
#Test
public void test2_updateData() throws Exception {
ABC abc = new ABC("NEW NAME");
System.out.println("------------------------------------------" + createdId); /// it is giving null
HttpEntity<ABC> requestBodyData = new HttpEntity<>(ABC);
ResponseEntity<ABC> response = restTemplate.exchange(
baseUrl + "/presenceType/" + createdId,
HttpMethod.PUT, requestBodyData, ABC.class);
Assert.assertTrue(HttpStatus.OK.equals(response.getStatusCode()));
createdId = response.getBody().getId();
}
}
the output of my execution
------------------------------------------null
What needs to be done to make this execution i.e calling of second function after the exection of first.
NOTE : The code also contains delete method which needs to be called after third.
Although it is not good practice to fix order in Tests. But If you are using JUnit above version 4.11, it has annotation #FixMethodOrder.
You can set order by method names.
Example:
import org.junit.runners.MethodSorters;
import org.junit.FixMethodOrder;
import org.junit.Test;
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class OrderTest {
#Test
public void test1() {
System.out.println("test1");
}
#Test
public void test2() {
System.out.println("test2");
}
}
For further reading #FixMethodOder
Junit Git Page: https://github.com/junit-team/junit4/wiki/test-execution-order
Custom Implemenation: https://memorynotfound.com/run-junit-tests-method-order/
FixMethodOrder not working for me, so I find another way to do this.
We can use #TestMethodOrder from Junit jupiter
https://junit.org/junit5/docs/5.5.0/api/org/junit/jupiter/api/TestMethodOrder.html
#Order annotation used to specify the sequence
Example code:
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DummyTest1 {
#Test
#Order(2)
public void read(){
System.out.println("read");
}
#Test
#Order(4)
public void delete(){
System.out.println("delete");
}
#Test
#Order(1)
public void create(){
System.out.println("create");
}
#Test
#Order(3)
public void update(){
System.out.println("update");
}
}
It will execute in sequence order order1, order2, order3, order4
So testing order will be,
create
read
update
delete

Junit for RESTTemplate Clients

I am trying to write Junit for one REST Webservice Client which uses RestTemplate.
Below is method call to REST Template:
final ResponseEntity<LogDateVO[]> result = restTemplate.postForEntity(url, LogDateInputVO, LogDateVO[].class);
In My Test Class I am trying some thing like below :
mockServer.expect(requestTo("http://abc.def.pvt:80/testOperations/api/traffic/logs/")).andExpect(method(HttpMethod.POST))
.andRespond(MockRestResponseCreators.withSuccess("{ \"id\" : \"42\", \"name\" : \"Holiday Inn\"}", MediaType.APPLICATION_JSON));
I am unable to get the result back and not able to continue with this approach, i need some help in getting this.
My intention is when my restTemplate is called it should check for above expect and return success with some data.
Assuming That class under test has a method which calls postForEntity using RestTemplate. For more info check this
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
#Service
public class SimpleRestService {
#Autowired
private RestTemplate restTemplate;
public String getMessage() {
String result;
String httpResult = restTemplate.getForObject("http://google.com",
String.class);
result = "Message SUCCESS result: " + httpResult;
return result;
}
}
Your Test class should will be like as below:
#ContextConfiguration(locations = {"classpath:aap.xml"})
public class SimpleRestServiceFunctionalTest extends AbstractJUnit4SpringContextTests {
#Autowired
private SimpleRestService simpleRestService;
#Autowired
private RestTemplate restTemplate;
private MockRestServiceServer mockServer;
#Before
public void setUp() {
mockServer = MockRestServiceServer.createServer(restTemplate);
}
#Test
public void testGetMessage() {
mockServer.expect(requestTo("http://google.com")).andExpect(method(HttpMethod.GET))
.andRespond(withSuccess("resultSuccess", MediaType.TEXT_PLAIN));
String result = simpleRestService.getMessage();
mockServer.verify();
assertThat(result, allOf(containsString("SUCCESS"), containsString("resultSuccess")));
}
#Test
public void testGetMessage_500() {
mockServer.expect(requestTo("http://google.com")).andExpect(method(HttpMethod.GET))
.andRespond(withServerError());
String result = simpleRestService.getMessage();
mockServer.verify();
assertThat(result, allOf(containsString("FAILED"), containsString("500")));
}
#Test
public void testGetMessage_404() {
mockServer.expect(requestTo("http://google.com")).andExpect(method(HttpMethod.GET))
.andRespond(withStatus(HttpStatus.NOT_FOUND));
String result = simpleRestService.getMessage();
mockServer.verify();
assertThat(result, allOf(containsString("FAILED"), containsString("404")));
}
}

Resources