如何将对象传递给 MockMVC post 中的 ModelAttrbiute?
How to pass an object to a ModelAttrbiute in MockMVC post?
用户模型:
@Entity
@Table(name="user")
public class User {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@NotBlank
@Column(name="username")
private String username;
@NotEmpty
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name="user_role", joinColumns = {@JoinColumn(name="user_id")},
inverseJoinColumns = {@JoinColumn(name="role_id")})
private Set<Role> roles;
}
控制器:
@RequestMapping(value = {"/users/edit/{id}"}, method = RequestMethod.POST)
public String editUser(ModelMap model, @Valid @ModelAttribute("user") User user, BindingResult result) {
if(result.hasErrors()) {
return "AddUserView";
}
return "redirect:/users";
}
使用 MockMVC 进行测试:
@Test
public void performUpdateUserTest() throws Throwable {
mockMvc.perform(post("/users/edit/{id}", user.getId())
.param("username", "User"));
}
好吧,我可以像往常一样使用 param() 传递参数 username。但是我应该用 ROLES 做什么呢?该字段是一个单独的对象。我无法使用 param() 传递它。那怎么可能考上呢?
我发现的唯一出路是创建一个实体并使用 .flashAttr() 传递它:
@Test
public void performUpdateUserTest() throws Throwable {
User user = new User("User", new HashSet<Role>(Arrays.asList(new Role("USER"))));
mockMvc.perform(post("/users/edit/{id}", user.getId())
.flashAttr("user", user));
}
但是,如果我需要测试由于 ROLES 字段中的绑定错误而无法更新用户怎么办(ROLES 不能为空,假设,它被设置为空)?因此,我无法创建已经存在绑定错误的用户(并将其与 .flashAttr 一起使用),因为将抛出异常。而且还是要分开传。
嗯,找了半天,发现应该给MockMVC加个转换器。例如,您可以阅读 HERE 是什么转换器。
我的项目中已经有了它,但没有意识到它不适用于 MockMVC。
因此,您可以像这样将转换器添加到 MockMVC:
@Autowired
private StringToRoleConverter stringToRoleConverter;
@Before
public void init() {
FormattingConversionService cs = new FormattingConversionService();
cs.addConverter(stringToRoleConverter);
mockMvc = MockMvcBuilders.standaloneSetup(userController)
.setConversionService(cs)
.build();
}
转换器本身:
@Component
public class StringToRoleConverter implements Converter<String, Role> {
@Autowired
private RoleService roleService;
@Override
public Role convert(String id) {
Role role = roleService.findById(Integer.valueOf(id));
return role;
}
}
然后我可以像这样添加参数:
mockMvc.perform(post("/users/edit/{id}", user.getId())
.param("roles", "2"))
虽然我在那里传递了一个字符串,但它将在 Spring 转换器的帮助下转换为 Role。
用户模型:
@Entity
@Table(name="user")
public class User {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@NotBlank
@Column(name="username")
private String username;
@NotEmpty
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name="user_role", joinColumns = {@JoinColumn(name="user_id")},
inverseJoinColumns = {@JoinColumn(name="role_id")})
private Set<Role> roles;
}
控制器:
@RequestMapping(value = {"/users/edit/{id}"}, method = RequestMethod.POST)
public String editUser(ModelMap model, @Valid @ModelAttribute("user") User user, BindingResult result) {
if(result.hasErrors()) {
return "AddUserView";
}
return "redirect:/users";
}
使用 MockMVC 进行测试:
@Test
public void performUpdateUserTest() throws Throwable {
mockMvc.perform(post("/users/edit/{id}", user.getId())
.param("username", "User"));
}
好吧,我可以像往常一样使用 param() 传递参数 username。但是我应该用 ROLES 做什么呢?该字段是一个单独的对象。我无法使用 param() 传递它。那怎么可能考上呢?
我发现的唯一出路是创建一个实体并使用 .flashAttr() 传递它:
@Test
public void performUpdateUserTest() throws Throwable {
User user = new User("User", new HashSet<Role>(Arrays.asList(new Role("USER"))));
mockMvc.perform(post("/users/edit/{id}", user.getId())
.flashAttr("user", user));
}
但是,如果我需要测试由于 ROLES 字段中的绑定错误而无法更新用户怎么办(ROLES 不能为空,假设,它被设置为空)?因此,我无法创建已经存在绑定错误的用户(并将其与 .flashAttr 一起使用),因为将抛出异常。而且还是要分开传。
嗯,找了半天,发现应该给MockMVC加个转换器。例如,您可以阅读 HERE 是什么转换器。 我的项目中已经有了它,但没有意识到它不适用于 MockMVC。
因此,您可以像这样将转换器添加到 MockMVC:
@Autowired
private StringToRoleConverter stringToRoleConverter;
@Before
public void init() {
FormattingConversionService cs = new FormattingConversionService();
cs.addConverter(stringToRoleConverter);
mockMvc = MockMvcBuilders.standaloneSetup(userController)
.setConversionService(cs)
.build();
}
转换器本身:
@Component
public class StringToRoleConverter implements Converter<String, Role> {
@Autowired
private RoleService roleService;
@Override
public Role convert(String id) {
Role role = roleService.findById(Integer.valueOf(id));
return role;
}
}
然后我可以像这样添加参数:
mockMvc.perform(post("/users/edit/{id}", user.getId())
.param("roles", "2"))
虽然我在那里传递了一个字符串,但它将在 Spring 转换器的帮助下转换为 Role。