如何在模拟另一个字段时使用真实实现自动装配字段?

时间:2015-11-10 15:20:02

标签: junit spring-boot mockito

我正在尝试对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。

3 个答案:

答案 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();

}