我有一个带有构造函数注入的控制器
@RestController
@RequestMapping("/user")
public class MainController {
private final UserMapper userMapper; // autowired by constructor below
public MainController(UserMapper userMapper) {
this.userMapper = userMapper;
}
@RequestMapping("/getChannels")
public String index() {
LoginUser user = userMapper.getUserByName("admin");
return "Channels: " + user.getChannels();
}
}
这是一个简单的类,工作正常。但是,当我尝试使用以下类运行 JUnit 测试时,我遇到了错误。
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class MainControllerTest {
private MockMvc mvc;
private final UserMapper userMapper;
public MainControllerTest(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(new MainController(userMapper)).build();
}
......
错误是:
java.lang.Exception: Test class should have exactly one public zero-argument constructor
我对上面的错误消息感到困惑,我如何用零参数构造函数注入 userMapper?我知道可以在主控制器中添加用户映射器的@Autowired,但不建议使用字段注入。请任何人指导我一种合适的构造函数注入和 MockMvc 测试方法。谢谢。
其他答案谈到使用注释,但在这里你的问题与使用注释没有任何关系。 请记住,作为Spring 4.3+,您不需要为依赖项注释构造函数,请参阅此处的更多信息。
事实上,你不需要尝试在测试类中模拟构造函数注入(MainControllerTest
(。您所需要的只是在应用程序上下文中将UserMapper
声明为 spring 组件,并且在测试类中,它将作为正在运行的应用程序自动注入到控制器中。
您的错误意味着什么:错误消息所说的所有 Junit 测试类都应该只有一个公共零参数构造函数,这是因为在您的场景等情况下,Junit 测试套件不知道如何实例化测试类。
在字段上使用@Autowire。不建议在生产代码中进行字段注入,因为它会使推理变得混乱(在何处以及为什么注入的内容(。但是测试上下文(尤其是像这样的上下文(很简单,所以不存在硬推理的陷阱。
@Autowired
private final UserMapper userMapper;
public MainControllerTest() { //remove me, implicit
}
此更改将解决此问题,因为 jUnit 将具有它理解的构造函数,并且能够实例化测试类。
您缺少MainController
构造函数的@Autowired
,并且始终使用构造函数注入来解决问题,如下所示:
@RestController
@RequestMapping("/user")
public class MainController {
private final UserMapper userMapper;
@Autowired
public MainController(UserMapper userMapper) {
this.userMapper = userMapper;
}
//add methods here
}
使用场注入不是最佳实践,请查看此处了解更多详细信息。
此外,要解决此问题,您需要更新您的 Test 类,如下所示:
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
public class MainControllerTest {
private MockMvc mvc;
@Mock
private UserMapper userMapper;
@InjectMocks
private MainController mainController = new MainController(userMapper);
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mvc = MockMvcBuilders.standaloneSetup(mainController)..build();
}
......
}