单元测试Spring MVC Controller:未绑定的java.util.Map数据

时间:2018-04-11 18:38:43

标签: spring unit-testing spring-mvc controller mockito

亲爱的开发者在stackoverflow,

我真的很感谢你帮助解决我在测试我的一个Spring MVC控制器时无法解决的棘手问题。

可以在此处找到整个代码存储库:https://github.com/peerpub/peerpub

环境:

  • Java 8
  • Maven 3.5
  • Spring Boot 2.0.1
  • Spring Framework 5.0.4
  • Thymeleaf 3
  • JUnit 5 + Mockito

问题描述:

在尝试使用Mockito / MockMVC的单元测试方法为DocTypeAdminCtrl.java进行详细测试时,我无法基于Map绑定数据,而简单String并且Boolean工作得很好。当我尝试在我的全栈集成测试中使用它时已经发生了同样的情况(已经尝试过)。

通过网络浏览器使用该应用程序时,不会出现此问题,因此这似乎完全与测试相关。

DocTypeAdminCtrlTest.java中名为editPost...()的所有测试均失败。示例摘录自mvn test

Tests run: 7, Failures: 3, Errors: 0, Skipped: 0, Time elapsed: 0.437 sec <<< FAILURE! - in de.fzj.peerpub.doc.doctype.DocTypeAdminCtrlTest
editPostFormSuccess  Time elapsed: 0.103 sec  <<< FAILURE!
java.lang.AssertionError: Status expected:<302> but was:<200>
at de.fzj.peerpub.doc.doctype.DocTypeAdminCtrlTest.editPostFormSuccess(DocTypeAdminCtrlTest.java:148)

editPostFormNonMatchingNames  Time elapsed: 0.046 sec  <<< FAILURE!
java.lang.AssertionError: Model attribute 'doctype' expected:   <DocTypeForm(name=vfAtXQ, displayName=01p14G7v22, system=false, multiDoc=true, attributes=[6Vuzhn, zKXSTl], mandatory={6Vuzhn=null, zKXSTl=true}, defaults={6Vuzhn=, zKXSTl=sooeOYb6Ld})> but was:<DocTypeForm(name=vfAtXQ, displayName=01p14G7v22, system=false, multiDoc=true, attributes=[6Vuzhn, zKXSTl], mandatory=null, defaults=null)>
at de.fzj.peerpub.doc.doctype.DocTypeAdminCtrlTest.editPostFormNonMatchingNames(DocTypeAdminCtrlTest.java:165)

editPostFormExceptionDTO  Time elapsed: 0.041 sec  <<< FAILURE!
java.lang.AssertionError: Model attribute 'doctype' expected:<DocTypeForm(name=GPzldO, displayName=mIV7Utta1Y, system=false, multiDoc=false, attributes=[8GsYhQ, bZGkd2], mandatory={8GsYhQ=null, bZGkd2=true}, defaults={8GsYhQ=SfoDlEiYAz, bZGkd2=k4uaLxx8yf})> but was:<DocTypeForm(name=GPzldO, displayName=mIV7Utta1Y, system=false, multiDoc=false, attributes=[8GsYhQ, bZGkd2], mandatory=null, defaults=null)>
 at  de.fzj.peerpub.doc.doctype.DocTypeAdminCtrlTest.editPostFormExceptionDTO(DocTypeAdminCtrlTest.java:210)

请注意,属性mandatorydefaults始终设置为null,同时存在于模型中。我确认即使我的自定义验证器DocTypeFormValidator.java也没有看到这些数据。这也导致我的editPostFormSuccess测试失败:由于属性设置为null,验证器不满意,绑定结果包含错误。

当我对单元/集成测试我的DocTypeAdminCtrl.java使用的任何类型的东西时,我很确定在我的控制器类或我的测试类中一定有一些缺失或错误。

MockMvcRequestBuilderUtils.postForm()可能存在错误(请参阅upstream),但我实际上不知道如何使用包含{{1}的测试数据编写备用post()请求}和Map。通过调试器查看List,所有数据似乎都存在,包括MockHttpServletRequestBuildermandatory,所以这可能是一个不太重要的事情要检查......?

引起我注意的一些可疑调试日志输出行:

defaults

在StackOverflow和Google上搜索这些错误并没有多大帮助......: - (

重现的步骤:

只需克隆我的仓库,切换到我的功能分支org.springframework.beans.BeanUtils - No property editor [java.util.MapEditor] found for type java.util.Map according to 'Editor' suffix convention org.springframework.core.annotation.AnnotationUtils - Failed to meta-introspect annotation interface org.springframework.web.bind.annotation.ModelAttribute: java.lang.NullPointerException 并运行oliver_dtsvc

那里有人有线索吗?非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

这与使用MockMvcRequestBuilderUtils.postForm()作为我的助手完全相关。

当我在editPostFormSuccess()中手动构建POST请求作为概念证明时,测试按预期运行:

ResultActions result = mvc.perform(post("/admin/doctypes/edit/{name}", this.valid.getName())
                                     .param("name", this.valid.getName())
                                     .param("displayName", this.valid.getDisplayName())
                                     .param("system", this.valid.getSystem().toString())
                                     .param("multiDoc", this.valid.getMultiDoc().toString())
                                     .param("attributes[0]", this.valid.getAttributes().get(0))
                                     .param("attributes[1]", this.valid.getAttributes().get(1))
                                     .param("mandatory["+this.valid.getAttributes().get(0)+"]", this.valid.getMandatory().get(this.valid.getAttributes().get(0)).toString())
                                     .param("mandatory["+this.valid.getAttributes().get(1)+"]", this.valid.getMandatory().get(this.valid.getAttributes().get(1)).toString())
                                     .param("defaults["+this.valid.getAttributes().get(0)+"]", this.valid.getDefaults().get(this.valid.getAttributes().get(0)))
                                     .param("defaults["+this.valid.getAttributes().get(1)+"]", this.valid.getDefaults().get(this.valid.getAttributes().get(1)))
);

因此,我将尝试弄清楚如何扩展/改进MockMvcRequestBuilderUtils,因为它有助于构建这些请求。 上游问题:https://github.com/f-lopes/spring-mvc-test-utils/issues/3