如何在模拟另一个字段的同时,将一个字段与实际实现自动连接



我正在尝试对Spring引导控制器进行单元测试,但我的一个@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自动连接自己并维护其spring环境上下文,就好像我只是在正常运行应用程序一样?

当我在@Before setup()方法中打印所有bean时,我可以在列表中看到DataValidationImpl。

当你用模拟你的控制器时

MockMvcBuilders.standaloneSetup(profileController).build();

控制器在上下文中被替换。由于您没有在其中注入任何IDataValidator,因此它为null。

最简单的解决方案是将实际的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();
}
}

如果我理解正确,您希望为UserProfileController注入真正的Validator和mock Service。

在这种情况下,我建议使用@ContextConfiguration annotaion,它允许在测试中配置上下文。您需要创建一个配置类:

@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);
    }
}

好吧,我发誓我第一次这么做了,但当试图为jny重新创建抛出的错误时,它确实起了作用。

我的解决方案是通过@Spy注释进行注入,并在我的@Before设置方法中从ApplicationContext获取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();
}

相关内容

  • 没有找到相关文章

最新更新