如何使用 MockMvc 的构造函数注入测试控制器
How to test a controller with constructor injection by MockMvc
我有一个带有构造函数注入的控制器
@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();
}
}
这是一个简单的 class,工作正常。但是,当我尝试 运行 使用以下 class 进行 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?
我知道可以在 MainController 中为 userMapper 添加 @Autowired,但是不推荐使用字段注入。
请任何人指导我一个合适的方法来进行构造函数注入和 MockMvc 测试。谢谢
在字段上使用@Autowire。不建议在生产代码中使用字段注入,因为它会使推理变得混乱(注入的内容和原因)。但是测试上下文(尤其是像这样的测试上下文)很简单,因此不存在硬推理的陷阱。
@Autowired
private final UserMapper userMapper;
public MainControllerTest() { //remove me, implicit
}
此更改将解决问题,因为 jUnit 将拥有一个它理解的构造函数,并且能够实例化测试 class。
您缺少 MainController
构造函数的 @Autowired
,请始终使用如下所示的构造函数注入来解决问题:
@RestController
@RequestMapping("/user")
public class MainController {
private final UserMapper userMapper;
@Autowired
public MainController(UserMapper userMapper) {
this.userMapper = userMapper;
}
//add methods here
}
使用字段注入不是最佳做法,请查看 here 了解更多详细信息。
此外,要解决此问题,您需要更新您的测试 class,如下所示:
@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();
}
......
}
其他答案都在谈论使用注解,但是这里你的问题与使用注解没有任何关系。请记住,spring 4.3+ 你不需要为依赖项注释构造函数,see more here.
事实上,您不需要在测试中尝试模拟构造函数注入 class (MainControllerTest
)。
您只需要在您的应用程序上下文中将 UserMapper
声明为 spring 组件,在您的测试中 class 它将作为您的 运行 应用程序自动注入到您的控制器中。
你的错误是什么意思:所有 Junit 测试 classes 错误消息说 应该有一个 public 零参数构造函数 那是因为 Junit在像您的场景这样的情况下,测试套件不知道如何实例化测试 class.
我有一个带有构造函数注入的控制器
@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();
}
}
这是一个简单的 class,工作正常。但是,当我尝试 运行 使用以下 class 进行 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? 我知道可以在 MainController 中为 userMapper 添加 @Autowired,但是不推荐使用字段注入。 请任何人指导我一个合适的方法来进行构造函数注入和 MockMvc 测试。谢谢
在字段上使用@Autowire。不建议在生产代码中使用字段注入,因为它会使推理变得混乱(注入的内容和原因)。但是测试上下文(尤其是像这样的测试上下文)很简单,因此不存在硬推理的陷阱。
@Autowired
private final UserMapper userMapper;
public MainControllerTest() { //remove me, implicit
}
此更改将解决问题,因为 jUnit 将拥有一个它理解的构造函数,并且能够实例化测试 class。
您缺少 MainController
构造函数的 @Autowired
,请始终使用如下所示的构造函数注入来解决问题:
@RestController
@RequestMapping("/user")
public class MainController {
private final UserMapper userMapper;
@Autowired
public MainController(UserMapper userMapper) {
this.userMapper = userMapper;
}
//add methods here
}
使用字段注入不是最佳做法,请查看 here 了解更多详细信息。
此外,要解决此问题,您需要更新您的测试 class,如下所示:
@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();
}
......
}
其他答案都在谈论使用注解,但是这里你的问题与使用注解没有任何关系。请记住,spring 4.3+ 你不需要为依赖项注释构造函数,see more here.
事实上,您不需要在测试中尝试模拟构造函数注入 class (MainControllerTest
)。
您只需要在您的应用程序上下文中将 UserMapper
声明为 spring 组件,在您的测试中 class 它将作为您的 运行 应用程序自动注入到您的控制器中。
你的错误是什么意思:所有 Junit 测试 classes 错误消息说 应该有一个 public 零参数构造函数 那是因为 Junit在像您的场景这样的情况下,测试套件不知道如何实例化测试 class.