Spring mvc BindingResult.getFieldValue()在测试上下文中为格式化值返回null
在SpringMVC应用程序中,我提交id并使用格式化程序将该id转换为对象。它在容器中运行良好 但是在单元测试环境中,我发现了一个问题 我模拟格式化程序总是返回我的测试值,这很好,因为它被注入ModelAttribute。但在BindingResult中,例如对result.getFieldValuelocation的调用返回null,但仅在MockMvc上下文中返回 这是测试用例:Spring mvc BindingResult.getFieldValue()在测试上下文中为格式化值返回null,spring-mvc,spring-mvc-test,Spring Mvc,Spring Mvc Test,在SpringMVC应用程序中,我提交id并使用格式化程序将该id转换为对象。它在容器中运行良好 但是在单元测试环境中,我发现了一个问题 我模拟格式化程序总是返回我的测试值,这很好,因为它被注入ModelAttribute。但在BindingResult中,例如对result.getFieldValuelocation的调用返回null,但仅在MockMvc上下文中返回 这是测试用例: /** * Tests the inventory update for existing inventor
/**
* Tests the inventory update for existing inventory records.
* @throws Exception
*/
@Test
public void testUpdateExistingProductInventory() throws Exception{
logger.entry();
VariantInventory oldInventory = new VariantInventory();
oldInventory.setId(20l);
Product product = ProductBuilder.buildBasicExisting();
Location location = new Location();
location.setId(3l);
ProductVariant variant = new ProductVariant();
variant.setId(2l);
// check the formatter is working
Mockito.when(mockProductFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(product);
Product p = mockProductFormatter.parse("1", null);
Assert.assertEquals(p, product);
// check the formatter is working
Mockito.when(mockLocationFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(location);
Location l = mockLocationFormatter.parse("3", null);
Assert.assertEquals(l, location);
// check the formatter is working
Mockito.when(mockVariantFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(variant);
ProductVariant pv = mockVariantFormatter.parse("2", null);
Assert.assertEquals(pv, variant);
// check the formatter is working
Mockito.when(mockInventoryFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(oldInventory);
VariantInventory v = mockInventoryFormatter.parse("20", null);
Assert.assertEquals(v, oldInventory);
this.mockMvc.perform(MockMvcRequestBuilders.post("/ajax/products/update/inventory")
.param("product", "1")
.param("variant", "2")
.param("location", "3")
.param("status", "ACTIVE")
.param("quantityOnHand", "30.5")
.param("lowStockQuantity", "10")
.param("inventory", "20")
)
.andExpect(status().isOk());
Mockito.verify(mockInventoryService, Mockito.times(1)).updateExisting(Mockito.eq(oldInventory), Mockito.any(VariantInventory.class));
logger.exit();
}
这是控制器的相对部分:
@RequestMapping(value = "/ajax/products/update/inventory", method= RequestMethod.POST)
public @ResponseBody
AJAXResponse updateProductInventory(@ModelAttribute ProductInventoryFormWrapper formWrapper, BindingResult result,
ModelMap map) {
logger.entry();
logger.debug("Getting product data");
if (!result.hasErrors()) {
inventoryValidator.validate(formWrapper, result);
}
}
然后跳过几个项目,这是失败的相关验证,我将位置作为字段传递
ValidationUtils.rejectIfEmptyOrWhitespace(errors, field, "required.field", new String[]{label});
该对象无法验证,因为它一定是一个bug
如果调试控制器,我观察到的是:
对象在FormWrapper中,属性在那里。
但是在BindingResult对象中,如果我调用'getFieldValue'location',这是spring验证代码中调用的,它将返回null,因此验证程序拒绝该值。
因此,由于某种原因,绑定结果没有注册格式化字段或其他内容。注意,这只发生在单元测试中,而不是容器中
有人知道怎么修理吗
快速编辑:
我做了更多的调试,但是AbstractPropertyBindingResult的这段代码失败了。在调用conversionService对其进行转换之前,该值一直正常。我还没有下载该方法以外的源代码,所以我不知道它失败的确切原因,但在convert方法的某个地方,它正从正确的值变为null。我猜测是因为我使用的是MockObjects,可能它调用了一些我没有预料到会返回值的东西
@Override
protected Object formatFieldValue(String field, Object value) {
String fixedField = fixedField(field);
// Try custom editor...
PropertyEditor customEditor = getCustomEditor(fixedField);
if (customEditor != null) {
customEditor.setValue(value);
String textValue = customEditor.getAsText();
// If the PropertyEditor returned null, there is no appropriate
// text representation for this value: only use it if non-null.
if (textValue != null) {
return textValue;
}
}
if (this.conversionService != null) {
// Try custom converter...
TypeDescriptor fieldDesc = getPropertyAccessor().getPropertyTypeDescriptor(fixedField);
TypeDescriptor strDesc = TypeDescriptor.valueOf(String.class);
if (fieldDesc != null && this.conversionService.canConvert(fieldDesc, strDesc)) {
return this.conversionService.convert(value, fieldDesc, strDesc);
}
}
return value;
}
好吧,这是一个很难回答的问题,所以我真的没想到会有人回答。但答案是这样的。我是对的,在验证中调用了Mock。因此,我不得不在格式化程序打印中添加一个额外的模拟方法:
// check the formatter is working
Mockito.when(mockInventoryFormatter.parse(((String)Mockito.anyObject()), ((Locale)Mockito.anyObject()))).thenReturn(oldInventory);
// this was added
Mockito.when(mockInventoryFormatter.print(Mockito.any(VariantInventory.class), Mockito.any(Locale.class))).thenReturn("20");