Я пытаюсь создать вспомогательный метод для преобразования тела ответа теста MockMvc обратно в мои доменные объекты и хочу сделать его универсальным для всех объектов.Это работает, когда ответом является объект, но не когда это список объектов.
Я использую com.fasterxml.jackson.databind.ObjectMapper и com.fasterxml.jackson.core.type.TypeReference для сопоставлениятело ответа обратно в мои объекты приложения.
Это методы, которые отображают ответы на объекты:
protected static <T> List<T> getResponseBodyList(MockHttpServletResponse response,
Class<T> clazz) throws JsonParseException, JsonMappingException,
UnsupportedEncodingException, IOException, InstantiationException, IllegalAccessException {
TypeReferenceListImpl<T> typeReference = new TypeReferenceListImpl<T>(clazz);
List<T> responseBody = new ObjectMapper().readValue(response.getContentAsString(),
typeReference);
return (List<T>) responseBody;
}
protected static <T> T getResponseBody(MockHttpServletResponse response, Class<T> clazz)
throws JsonParseException, JsonMappingException, UnsupportedEncodingException, IOException {
TypeReferenceImpl<T> typeReference = new TypeReferenceImpl<T>(clazz);
T responseBody = new ObjectMapper().readValue(response.getContentAsString(), typeReference);
return responseBody;
}
private static class TypeReferenceImpl<T> extends TypeReference<T> {
protected final Type type;
protected TypeReferenceImpl(Class<T> clazz) {
type = clazz;
}
public Type getType() {
return type;
}
}
private static class TypeReferenceListImpl<T> extends TypeReference<T> {
protected final Type type;
protected TypeReferenceListImpl(Class<T> clazz) throws InstantiationException,
IllegalAccessException {
List<T> list = new ArrayList<>();
list.add(clazz.newInstance());
type = list.getClass();
}
public Type getType() {
return type;
}
}
В своих тестах я вызываю эти методы следующим образом:
// This test works:
@Test
public void getUserTest() throws Exception {
when(applicationUserServiceMock.loadUserByUsername(applicationUser.getUsername())).thenReturn(
applicationUser);
MockHttpServletResponse response = executeGet(API_V1_ADMIN_APPLICATION_USERS + applicationUser
.getUsername());
ApplicationUser responseBody = getResponseBody(response, ApplicationUser.class);
verifyResponseStatus(response, HttpStatus.OK.value());
assertEquals(applicationUser, responseBody);
}
//Test that fails:
@Test
public void getUsersTest() throws Exception {
when(applicationUserServiceMock.getAllUsers()).thenReturn(applicationUsersList);
MockHttpServletResponse response = executeGet(API_V1_ADMIN_APPLICATION_USERS);
List<ApplicationUser> responseBody = getResponseBodyList(response, ApplicationUser.class);
verifyResponseStatus(response, HttpStatus.OK.value());
assertEquals(3, responseBody.size()); // This assert passes
assertEquals(applicationUsersList, responseBody);
// Fails in the last assertEquals. Debugging it, I can see responseBody ends up being a List of LinkedHashMaps.
// I assume because I get a list of Objects instead of a list of ApplicationUsers.
}
Мне нужно, чтобы это работало (по крайней мере, в качестве первого подхода), чтобы получить TypeReferenceListImpl для возврата типа списка реального класса T, который я передаю как параметр Class clazz.Но я не могу создать список этого конкретного типа на основе объекта Class, чтобы получить его тип с помощью getClass ().Это последний из многих подходов, которые я использовал, чтобы получить этот тип, но ни один из них не сработал.
Возможно ли это вообще?Или у кого-то есть другой подход для решения этой проблемы?
Я пытаюсь создать универсальный метод для получения тела ответа для всех тестов контроллера, которые возвращают различные типы списков объектов
трассировка стека:
java.lang.AssertionError: expected:<[{
"id" : 1001,
"username" : "goku",
"password" : null,
"email" : "goku@dbz.com",
"firstName" : "Goku",
"lastName" : "Son",
"lastLogin" : null,
"authorities" : [ {
"id" : 10,
"name" : "ADMIN_ROLE"
} ],
"accountNonExpired" : true,
"accountNonLocked" : true,
"credentialsNonExpired" : true,
"enabled" : true
}, {
"id" : 1002,
"username" : "gohan",
"password" : null,
"email" : "gohan@dbz.com",
"firstName" : null,
"lastName" : null,
"lastLogin" : null,
"authorities" : [ {
"id" : null,
"name" : "ROLE_USER"
} ],
"accountNonExpired" : true,
"accountNonLocked" : true,
"credentialsNonExpired" : true,
"enabled" : true
}, {
"id" : 1003,
"username" : "goten",
"password" : null,
"email" : "goten@dbz.com",
"firstName" : null,
"lastName" : null,
"lastLogin" : null,
"authorities" : [ {
"id" : null,
"name" : "ROLE_USER"
} ],
"accountNonExpired" : true,
"accountNonLocked" : true,
"credentialsNonExpired" : true,
"enabled" : true
}]> but was:<[{id=1001, username=goku, password=null, email=goku@dbz.com, firstName=Goku, lastName=Son, lastLogin=null, authorities=[{id=10, name=ADMIN_ROLE}], accountNonExpired=true, accountNonLocked=true, credentialsNonExpired=true, enabled=true}, {id=1002, username=gohan, password=null, email=gohan@dbz.com, firstName=null, lastName=null, lastLogin=null, authorities=[{id=null, name=ROLE_USER}], accountNonExpired=true, accountNonLocked=true, credentialsNonExpired=true, enabled=true}, {id=1003, username=goten, password=null, email=goten@dbz.com, firstName=null, lastName=null, lastLogin=null, authorities=[{id=null, name=ROLE_USER}], accountNonExpired=true, accountNonLocked=true, credentialsNonExpired=true, enabled=true}]>
at org.junit.Assert.fail(Assert.java:88)
at org.junit.Assert.failNotEquals(Assert.java:834)
at org.junit.Assert.assertEquals(Assert.java:118)
at org.junit.Assert.assertEquals(Assert.java:144)
at com.nicobrest.kamehouse.admin.controller.ApplicationUserControllerTest.getUsersTest(ApplicationUserControllerTest.java:91)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
...
Обновление: В случае, если кто-то столкнется с этим, вам не нужно вручную создавать список, у Jackson Mapper уже есть встроенный способ создания ящикасписок универсального типа, который вы передаете (facepalm), поэтому мое окончательное решение использует эти 2 метода:
protected static <T> List<T> getResponseBodyList(MockHttpServletResponse response, Class<T> clazz)
throws JsonParseException, JsonMappingException, UnsupportedEncodingException, IOException,
InstantiationException, IllegalAccessException {
ObjectMapper mapper = new ObjectMapper();
List<T> responseBody = mapper.readValue(response.getContentAsString(),
mapper.getTypeFactory().constructCollectionType(List.class, clazz));
return responseBody;
}
protected static <T> T getResponseBody(MockHttpServletResponse response, Class<T> clazz)
throws JsonParseException, JsonMappingException, UnsupportedEncodingException, IOException {
ObjectMapper mapper = new ObjectMapper();
T responseBody = mapper.readValue(response.getContentAsString(),
mapper.getTypeFactory().constructType(clazz));
return responseBody;
}
Спасибо @deadpool за ваши предложения и за то, что я посмотрел на него с другой точки зрения