this is my code ,i can get proxy from getActionProxy,but i can't get Action.
that's my first time test Struts2 action and don't know error.
The TestCase ClaimActionTest extends StrutsSpringTestCase.
#Test
public void testPrepareAddClaim() throws Exception{
ActionProxy proxy = getActionProxy("/claim.action/prepareAddClaim.do");
System.out.println(proxy.getActionName());
System.out.println(proxy.getNamespace());
System.out.println(proxy.getAction());
ClaimAction action = (ClaimAction) proxy.getAction();
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("registNo", "34244432432");
ActionContext actionContext = proxy.getInvocation().getInvocationContext();
actionContext.setParameters(paramMap);
String result = proxy.execute();
assertEquals("success", result);
}
Related
I have the a reducer class that I wanted to write test cases:
Reduce class:
public class MyReducer extends Reducer<Text, Text, NullWritable, Text> {
private static final Logger LOG = LogManager.getLogger(MyReducer.class);
public static List<String> l1 = new ArrayList<String>();
String id = null;
private MultipleOutputs<NullWritable, Text> mos;
#Override
public void setup(final Context context) throws IOException, InterruptedException {
mos = new MultipleOutputs<NullWritable, Text>(context);
final Path[] uris = DistributedCache.getLocalCacheFiles(context.getConfiguration());
try {
final BufferedReader readBuffer1 = new BufferedReader(new FileReader(uris[0].toString()));
String line;
while ((line = readBuffer1.readLine()) != null) {
l1.add(line);
}
readBuffer1.close();
} catch (Exception e) {
LOG.error(e);
}
}
public void reduce(final Text key, final Iterable<Text> values, final Context context)
throws IOException, InterruptedException {
final String[] key1 = key.toString().split("-");
final String keyA = key1[10];
final String date = key1[1];
/* Some condition check */
mos.write(NullWritable.get(), new Text(inputEventValue), keyA + "//date=" +
date.substring(0, 4) + "-" + date.substring(4, 6));
}
#Override
public void cleanup(final Context context) throws IOException, InterruptedException {
mos.close();
}
}
Test Case looks like :
#RunWith(MockitoJUnitRunner.class)
public class MyTest {
#Mock
private MyReducer.Context mockContext;
MyReducer reducer;
MultipleOutputs<NullWritable, Text> mos;
#Before
public void setUp() {
reducer = new MyReducer();
}
#Test
public void myReducerTest() throws Exception {
MyReducer spy = PowerMockito.spy(new MyReducer());
doNothing().when(spy).setup(mockContext);
mos = new MultipleOutputs<NullWritable, Text>(mockContext);
List<Text> sline = new ArrayList<>() ;
List<String> l1 = new ArrayList<String>();
l1.add(“1234”);
sline.add(new Text(“xyz”));
Whitebox.setInternalState(MyReducer.class,”l1", l1);
Whitebox.setInternalState(MyReducer.class,"mos",mos);
reducer.reduce(new Text(“xyz-20200101-1234),sline,mockContext);
}
#After
public void tearDown() throws Exception {
/*
* this will do the clean up part
*/
verifyNoMoreInteractions(mockContext);
}
When running in Debug mode it goes to the reducer's reduce method and fails with NullPointerException where mos write statement is?
Complete Stack trace:
java.lang.NullPointerException
at org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.getNamedOutputsList(MultipleOutputs.java:196)
at org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.<init>(MultipleOutputs.java:324)
at MyTest.myeducerTest
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:101)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53)
Mocking mos errors as mos is not a static.
Any suggestion.
Junit - ReduceDriver, withInput, withOutput,testRun doesn't work.
Thanks.
I tried mocking Multiple outputs as suggested:
import org.apache.hadoop.mapreduce.lib.output.MultipleOutputs;
#Mock
private MyReducer.Context mockContext;
List<String> namedOut = new ArrayList<>();
namedOut.add("NM1");
namedOut.add("NM2");
MultipleOutputs spy = PowerMockito.spy(new MultipleOutputs<>(mockContext));
when(spy, "getNamedOutputsList(mockContext)").thenReturn(namedOut);
But this gives me error : org.powermock.reflect.exceptions.MethodNotFoundException: no method found with name 'getNamedOutputsList(() anyObject())' with parameter types : [] in class org.apache.hadoop.mapreduce.lib.output.MultipleOutputs.
Looks like you did not define what mockContext.getContext() should return for your test, so it returns null and fails.
Based on this sourcecode the methods looks like this (so you might use a different version):
private static List<String> getNamedOutputsList(JobContext job) {
List<String> names = new ArrayList<String>();
StringTokenizer st = new StringTokenizer(
job.getConfiguration().get(MULTIPLE_OUTPUTS, ""), " ");
while (st.hasMoreTokens()) {
names.add(st.nextToken());
}
return names;
}
JobContext seems to refer to your mock Reducer.Context mockContext, so you need to define the appropriate behaviour so that it returns what it is supposed to return.
Note that this call originates from the constructor of MultipleOutputs.
Also take note of the static getCountersEnabled method that is invoked from the constructor and interacts with the context.
Mocking mos errors as mos is not a static.
You could probably use reflections to put a mocked version of mos into your MyReducer class.
Check here for some example on how to mock a private static field.
Edit:
If you try to mock the conig do it like this:
Configuration config = Mockito.mock(Configuration.class);
when(mockContext.getConfiguration()).thenReturn(config);
As far as I see the get that are invoked on the configuration object always provide a default value, so it shouldn't matter if the key/value pair is in there or not.
This question already has answers here:
How to call a method in another class of the same package?
(8 answers)
Closed 4 years ago.
I am new and beginner in Java world. I have this code
public class Test2 {
public static void main(String[] args) throws IOException {
try {
String url = "http://www.metalbulletin.com/Login.html?ReturnURL=%2fdefault.aspx&";
String articleURL = "https://www.metalbulletin.com/Article/3838710/Home/CHINA-REBAR-Domestic-prices-recover-after-trading-pick-up.html";
Connection.Response loginForm = Jsoup.connect(url)
.method(Connection.Method.GET)
.execute();
Document welcomePage = loginForm.parse();
Element formElement = welcomePage.body().getElementsByTag("form").get(0);
String formAction = formElement.attr("action");
Elements input = welcomePage.select("input[name=idsrv.xsrf]");
String securityTokenValue =input.attr("value");
Connection.Response mainPage = Jsoup.connect("https://account.metalbulletin.com"+formAction)
.data("idsrv.xsrf", securityTokenValue)
.data("username", "ifiih#rupayamail.com")
.data("password", "Kh457544")
.cookies(loginForm.cookies())
.method(Connection.Method.POST)
.execute();
Map<String, String> cookies = mainPage.cookies();
System.out.println("\n\nloginForm.cookies()==>\n"+loginForm.cookies());
System.out.println("\n\nmainPage.cookies()==>\n"+mainPage.cookies());
Document articlePage = Jsoup.connect(articleURL).cookies(cookies).get();
Element article = articlePage.getElementById("article-body");
Elements lead1 = article.getElementsByClass("articleContainer");
System.out.println("\n\nNews Article==>\n"+lead1);
} catch (IOException e) {
e.printStackTrace();
}
}
}
How can I refactor to this:
private Map<String, String> cookies = new HashMap<String, String>();
private Document get(String url) throws IOException {
Connection connection = Jsoup.connect(url);
for (Map.Entry<String, String> cookie : cookies.entrySet()) {
connection.cookie(cookie.getKey(), cookie.getValue());
}
Response response = connection.execute();
cookies.putAll(response.cookies());
return response.parse();
}
I am not sure as to how I can call this private Document get(String url) method. It may seems to be stupid question but very important for me.
How can I call it within same class?
to do that, the easiest and more efficient solution to retrieve the Document and also the Map of Cookies, would be to create a new class called TestThreadHandler as it follows:
public class TestThreadHandler implements Runnable {
private String url;
private Document doc;
private Map<String, String> cookies;
private Semaphore barrier;
public TestThreadHandler (String url, Document doc, Map<String, String> cookies, Semaphore barrier) {
this.url = url;
this.doc = doc;
this.cookies = cookies;
this.barrier = barrier;
}
public void run () {
try {
Connection connection = Jsoup.connect(this.url);
for (Map.Entry<String, String> cookie : this.cookies.entrySet()) {
connection.cookie(cookie.getKey(), cookie.getValue());
}
Response response = connection.execute();
this.cookies.putAll(response.cookies());
this.doc = response.parse();
} catch (IOException e) {
e.printStackTrace();
}
this.barrier.release();
}
}
And call that Thread from your Test2 class from wherever you want to call it, but a sample call to that Thread would be:
public class Test2 {
public static void main(String[] args) throws IOException {
try {
...
String url = "https://www.google.com";
Document doc;
Map<String, String> cookies = new HashMap<String, String>();
Semaphore barrier = new Semaphore(0);
Thread taskThread = new Thread( new TestThreadHandler(url, doc, cookies, barrier) );
taskThread.start();
barrier.acquireUninterruptibly(1); // Wait until Thread ends
// NOW YOU HAVE BOTH DOC AND COOKIES FILLED AS DESCRIBED IN TestThreadHandler
...
} catch (IOException e) {
e.printStackTrace();
}
}
}
Doing that you can overwrite the variables you are passing as argument to the Thread and get both the Cookies and the JSOUP Document.
For further explanation check the Java doc of ThreadHandling or feel free to ask me!
Hope this helped you! +1
I am planning to write an ActionFilter for business validation and in which some services will be resolved via Service Locator(I know this is not good practice and as far as possible i avoid Service Locator pattern, but for this case i want to use it).
OnActionExecuting method of the filter is something like this:
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
// get validator for input;
var validator = actionContext.HttpContext.RequestServices.GetService<IValidator<TypeOfInput>>();// i will ask another question for this line
if(!validator.IsValid(input))
{
//send errors
}
}
Is it possible to write unit test for above ActionFilterand how?
Here is an sample on how to create a mock (using XUnit and Moq framework) to verify that the IsValid method is called and where the mock returns an false.
using Dealz.Common.Web.Tests.Utils;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using System;
using Xunit;
namespace Dealz.Common.Web.Tests.ActionFilters
{
public class TestActionFilter
{
[Fact]
public void ActionFilterTest()
{
/****************
* Setup
****************/
// Create the userValidatorMock
var userValidatorMock = new Mock<IValidator<User>>();
userValidatorMock.Setup(validator => validator
// For any parameter passed to IsValid
.IsValid(It.IsAny<User>())
)
// return false when IsValid is called
.Returns(false)
// Make sure that `IsValid` is being called at least once or throw error
.Verifiable();
// If provider.GetService(typeof(IValidator<User>)) gets called,
// IValidator<User> mock will be returned
var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock.Setup(provider => provider.GetService(typeof(IValidator<User>)))
.Returns(userValidatorMock.Object);
// Mock the HttpContext to return a mockable
var httpContextMock = new Mock<HttpContext>();
httpContextMock.SetupGet(context => context.RequestServices)
.Returns(serviceProviderMock.Object);
var actionExecutingContext = HttpContextUtils.MockedActionExecutingContext(httpContextMock.Object, null);
/****************
* Act
****************/
var userValidator = new ValidationActionFilter<User>();
userValidator.OnActionExecuting(actionExecutingContext);
/****************
* Verify
****************/
// Make sure that IsValid is being called at least once, otherwise this throws an exception. This is a behavior test
userValidatorMock.Verify();
// TODO: Also Mock HttpContext.Response and return in it's Body proeprty a memory stream where
// your ActionFilter writes to and validate the input is what you desire.
}
}
class User
{
public string Username { get; set; }
}
class ValidationActionFilter<T> : IActionFilter where T : class, new()
{
public void OnActionExecuted(ActionExecutedContext context)
{
throw new NotImplementedException();
}
public void OnActionExecuting(ActionExecutingContext actionContext)
{
var type = typeof(IValidator<>).MakeGenericType(typeof(T));
var validator = (IValidator<T>)actionContext.HttpContext
.RequestServices.GetService<IValidator<T>>();
// Get your input somehow
T input = new T();
if (!validator.IsValid(input))
{
//send errors
actionContext.HttpContext.Response.WriteAsync("Error");
}
}
}
internal interface IValidator<T>
{
bool IsValid(T input);
}
}
HttpContextUtils.cs
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Collections.Generic;
namespace Dealz.Common.Web.Tests.Utils
{
public class HttpContextUtils
{
public static ActionExecutingContext MockedActionExecutingContext(
HttpContext context,
IList<IFilterMetadata> filters,
IDictionary<string, object> actionArguments,
object controller
)
{
var actionContext = new ActionContext() { HttpContext = context };
return new ActionExecutingContext(actionContext, filters, actionArguments, controller);
}
public static ActionExecutingContext MockedActionExecutingContext(
HttpContext context,
object controller
)
{
return MockedActionExecutingContext(context, new List<IFilterMetadata>(), new Dictionary<string, object>(), controller);
}
}
}
As you can see, it's quite a mess, you need to create plenty of mocks to simulate different responses of the actuall classes, only to be able to test the ActionAttribute in isolation.
I like #Tseng's above answer but thought of giving one more answer as his answer covers more scenarios (like generics) and could be overwhelming for some users.
Here I have an action filter attribute which just checks the ModelState and short circuits(returns the response without the action being invoked) the request by setting the Result property on the context. Within the filter, I try to use the ServiceLocator pattern to get a logger to log some data(some might not like this but this is an example)
Filter
public class ValidationFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<ValidationFilterAttribute>>();
logger.LogWarning("some message here");
context.Result = new JsonResult(new InvalidData() { Message = "some messgae here" })
{
StatusCode = 400
};
}
}
}
public class InvalidData
{
public string Message { get; set; }
}
Unit Test
[Fact]
public void ValidationFilterAttributeTest_ModelStateErrors_ResultInBadRequestResult()
{
// Arrange
var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock
.Setup(serviceProvider => serviceProvider.GetService(typeof(ILogger<ValidationFilterAttribute>)))
.Returns(Mock.Of<ILogger<ValidationFilterAttribute>>());
var httpContext = new DefaultHttpContext();
httpContext.RequestServices = serviceProviderMock.Object;
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
var actionExecutingContext = new ActionExecutingContext(
actionContext,
filters: new List<IFilterMetadata>(), // for majority of scenarios you need not worry about populating this parameter
actionArguments: new Dictionary<string, object>(), // if the filter uses this data, add some data to this dictionary
controller: null); // since the filter being tested here does not use the data from this parameter, just provide null
var validationFilter = new ValidationFilterAttribute();
// Act
// Add an erorr into model state on purpose to make it invalid
actionContext.ModelState.AddModelError("Age", "Age cannot be below 18 years.");
validationFilter.OnActionExecuting(actionExecutingContext);
// Assert
var jsonResult = Assert.IsType<JsonResult>(actionExecutingContext.Result);
Assert.Equal(400, jsonResult.StatusCode);
var invalidData = Assert.IsType<InvalidData>(jsonResult.Value);
Assert.Equal("some messgae here", invalidData.Message);
}
I want to use cookies in Robospice, I have spice service:
public class JsonSpiceService extends SpringAndroidSpiceService {
public RestTemplate createRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
MappingJacksonHttpMessageConverter jsonConverter = new MappingJacksonHttpMessageConverter();
FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
final List<HttpMessageConverter<?>> listHttpMessageConverters = restTemplate.getMessageConverters();
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
restTemplate.setRequestFactory( httpRequestFactory );
listHttpMessageConverters.add(jsonConverter);
listHttpMessageConverters.add(formHttpMessageConverter);
listHttpMessageConverters.add(stringHttpMessageConverter);
restTemplate.setMessageConverters(listHttpMessageConverters);
return restTemplate;
}
public CacheManager createCacheManager(Application application) throws CacheCreationException {
CacheManager cacheManager = new CacheManager();
List< Class< ? >> classCollection = new ArrayList< Class< ? >>();
classCollection.add(User.class);
JacksonObjectPersisterFactory jacksonObjectPersisterFactory = new JacksonObjectPersisterFactory(application);
cacheManager.addPersister(jacksonObjectPersisterFactory);
return cacheManager;
}
}
and my Request class:
public class Request extends SpringAndroidSpiceRequest<HttpModel> {
private Context context;
private HttpMethod httpMethod;
private MultiValueMap<String, String> body;
private String link;
private String what;
private Object object;
public Request(Context context, HttpMethod httpMethod, MultiValueMap<String, String> body, String link, String what, Object object) {
super(HttpModel.class);
this.context = context;
this.httpMethod = httpMethod;
this.body = body;
this.link = link;
this.what = what;
this.object = object;
}
#Override
public HttpModel loadDataFromNetwork() throws Exception {
HttpModel httpModel;
HttpHeaders headers = new HttpHeaders();
HttpEntity<?> requestEntity;
if (!what.equals(LOGIN)) {
headers.setContentType(MediaType.APPLICATION_JSON);
} else {
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
}
requestEntity = new HttpEntity<Object>(body, headers);
ResponseEntity<HttpModel> responseEntity = getRestTemplate().exchange(link, httpMethod, requestEntity, HttpModel.class);
httpModel = responseEntity.getBody();
return httpModel;
}
}
How can i get cookie from response?I try add CookieManager to my Request class, but dont'work:
final CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault(cookieManager);
In postman Cookie look like this:
enter link description here
CookieManager is used only for managing cookies in your application's WebViews.
You can use responseEntity.getHeaders().get(COOKIE). You can also try SET_COOKIE or SET_COOKIE2 keys instead of COOKIE, depending on your server's response.
Can someone help on this?
I am getting the below exception(org.springframework.web.HttpMediaTypeNotSupportedException) when I run this test.
In the response I get this Headers.
Headers = {Accept=[application/octet-stream, text/plain;charset=ISO-8859-1, application/xml, text/xml, application/x-www-form-urlencoded, application/+xml, multipart/form-data, application/json;charset=UTF-8, application/+json;charset=UTF-8, /]}
The add method in the controller is
#RequestMapping(value = "/addTrain", method = RequestMethod.POST)
public #ResponseBody void addTrain(#RequestBody Train train) {
trainService.addTrain(train);
}
I am doing JUnit test for a method. Below is my Test class and MockHttpServletRequest and MockHttpSErvletResponse.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/config/webapp-config.xml" })
#WebAppConfiguration
public class TrainControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#InjectMocks
TrainController trainController;
#Mock
private TrainService trainService;
private final List<Train> trainList = new ArrayList<Train>();
private Train train;
#Before
public void setUp() throws Exception {
// Process mock annotations
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
train = new Train();
train.setId(12L);
train.setName("chennai");
train.setSpeed(100);
train.setDiesel(true);
Train train1 = new Train();
train1.setId(15L);
train1.setName("kovai");
train1.setSpeed(150);
train1.setDiesel(false);
trainList.add(train);
trainList.add(train1);
}
#Test
public void testAddTrainList() throws Exception {
Mockito.doNothing().when(trainService).addTrain(train);
this.mockMvc.perform(post("/trains/addTrain")).andDo(print()).andExpect(status().isOk());
}
}
The request and reponse are below:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /trains/addTrain
Parameters = {}
Headers = {}
Handler:
Type = com.xvitcoder.angualrspringapp.controller.TrainController
Method = public void com.xvitcoder.angualrspringapp.controller.TrainController.addTrain(com.xvitcoder.angualrspringapp.beans.Train)
Async:
Was async started = false
Async result = null
**Resolved Exception:
Type = org.springframework.web.HttpMediaTypeNotSupportedException**
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
**MockHttpServletResponse:
Status = 415
Error message = null**
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Your request has to specify the Content-type header from one of the acceptable ones.
Try changing your mock request as below:
this.mockMvc.perform(post("/trains/addTrain").contentType(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isOk());
Resolved Exception:
Type = org.springframework.http.converter.HttpMessageNotReadableException