我正在尝试对Spring-boot控制器进行单元测试,并且我的一个@Autowired
字段将返回null。
我在此控制器中有两个自动连接的字段:
public class UserProfileController{
@Autowired
private UserProfileService profileService;
@Autowired
private IDataValidator dataValidatorImpl;
我的测试课如下:
@RunWith(SpringJUnit4ClassRunner.class)
@WebIntegrationTest
@SpringApplicationConfiguration(classes = UserProfileServiceApplication.class)
public class ControllerTest {
private MockMvc mockMvc;
@Mock
UserProfileService profileServiceMock;
@Autowired
ApplicationContext actx;
@InjectMocks
private UserProfileController profileController;
@Before
public void setup() {
// Process mock annotations
String[] asdf = actx.getBeanDefinitionNames();
for (int i = 0; i < asdf.length; i++){
System.out.println(asdf[i]);
}
MockitoAnnotations.initMocks(this);
// Setup Spring test in standalone mode
this.mockMvc = MockMvcBuilders.standaloneSetup(profileController).build();
}
/**
* All this does is verify that we return the correct datatype and HTTP status
* @throws Exception
*/
@Test
public void testGetProfileSuccess() throws Exception {
Mockito.when(profileServiceMock.getProfile(Mockito.any(HashMap.class))).thenReturn(new HashMap<String, Object>());
mockMvc.perform(get("http://localhost:8095/UserName?tenantId=tenant1"))
.andExpect(status().isOk())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8));
//verify profileService was only used once
Mockito.verify(profileServiceMock, Mockito.times(1)).getProfile(Mockito.any(HashMap.class));
//verify we're done interacting with profile service
Mockito.verifyNoMoreInteractions(profileServiceMock);
}
如果我在测试类中保持IDataValidator不变,它会出现null并且我得到一个NPE。如果我@Spy
DataValidatorImpl,它无法从Spring环境中找到它需要工作的属性。
我怎样才能让IDataValidator自动自动保持其弹簧环境上下文,就好像我只是正常运行应用程序一样?
当我在@Before
setup()方法中打印所有bean时,我可以在列表中看到DataValidationImpl。
答案 0 :(得分:1)
使用
模拟控制器时MockMvcBuilders.standaloneSetup(profileController).build();
在上下文中替换控制器。由于您没有在其中注入任何IDataValidator
,因此它为空。
最简单的解决方案是将真实IDataValidator
自动装入测试类并将其注入控制器。
在您的控制器中:
public class UserProfileController{
private UserProfileService profileService;
private IDataValidator dataValidatorImpl;
@Autowired
public UserProfileController(UserProfileService profileService, IDataValidator dataValidatorImpl) {
this.profileService = profileService;
this.dataValidatorImpl = dataValidatorImpl;
}
在你的测试中:
@RunWith(SpringJUnit4ClassRunner.class)
@WebIntegrationTest
@SpringApplicationConfiguration(classes = UserProfileServiceApplication.class)
public class ControllerTest {
private MockMvc mockMvc;
private UserProfileService profileService;
@Autowired
private IDataValidator dataValidator;
@Before
public void setup() {
UserProfileService profileService = Mockito.mock(UserProfileService.class);
UserProfileController controller = new UserProfileController(profileService, dataValidator);
// Setup Spring test in standalone mode
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
}
答案 1 :(得分:0)
如果我理解正确,您希望使用真实的Validator和模拟服务注入UserProfileController
。
在这种情况下,我建议使用@ContextConfiguration
注释,允许在测试中配置上下文。您需要创建一个Configuration类:
@RunWith(SpringJUnit4ClassRunner.class)
@WebIntegrationTest
@SpringApplicationConfiguration(classes = UserProfileServiceApplication.class)
public class ControllerTest {
private MockMvc mockMvc;
@Mock
UserProfileService profileServiceMock;
@Autowired
ApplicationContext actx;
//comment this line out
//@InjectMocks
@Autowired
private UserProfileController profileController;
@Before
public void setup() {
// Process mock annotations
String[] asdf = actx.getBeanDefinitionNames();
for (int i = 0; i < asdf.length; i++){
System.out.println(asdf[i]);
}
//comment this line out
//MockitoAnnotations.initMocks(this);
@Configuration
public static class Config {
//wire validator - if it is not wired by other configurations
@Bean
Validator validator() {
return new Validaor();
}
//wire mock service
@Bean
public UserProfileService profileService() {
return mock(UserProfileService.class);
}
}
答案 2 :(得分:0)
好的,我发誓我是第一次这样做但是当我试图重新创建为jny抛出的错误时,它确实有效。
我的解决方案是通过@Spy
注释注入,并从ApplicationContext
设置方法中的@Before
获取bean。
public class ControllerTest {
private MockMvc mockMvc;
@Mock
UserProfileService profileServiceMock;
@Spy
IDataValidator dataValidator;
@Autowired
ApplicationContext actx;
@InjectMocks
private UserProfileController profileController;
@Before
public void setup() {
dataValidator = (IDataValidator) actx.getBean("dataValidatorImpl");
MockitoAnnotations.initMocks(this);
// Setup Spring test in standalone mode
this.mockMvc = MockMvcBuilders.standaloneSetup(profileController).build();
}