Spring JUnit: 如何在自动连接组件中模拟自动连接组件

我有一个我想测试的 Spring 组件,这个组件有一个自动连接的属性,为了进行单元测试,我需要更改这个属性。问题是,这个类在 post-construction 方法中使用了 autowired 组件,所以在实际使用之前我无法替换它(比如通过 RefectionTestUtils)。

我该怎么做?

这就是我想测试的类:

@Component
public final class TestedClass{


@Autowired
private Resource resource;


@PostConstruct
private void init(){
//I need this to return different result
resource.getSomething();
}
}

这是一个测试案例的基础:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= "classpath:applicationContext.xml")
public class TestedClassTest{


@Autowired
private TestedClass instance;


@Before
private void setUp(){
//this doesn't work because it's executed after the bean is instantiated
ReflectionTestUtils.setField(instance, "resource", new Resource("something"));
}
}

在调用 poststruct 方法之前,是否有其他方法来替换资源?喜欢告诉 Spring JUnit 运行器自动连接不同的实例吗?

161979 次浏览

您可以提供一个新的 testContext.xml,其中定义的 @Autowired bean 是您测试所需的类型。

你可以使用 莫基托。我不确定具体使用 PostConstruct,但这通常是有效的:

// Create a mock of Resource to change its behaviour for testing
@Mock
private Resource resource;


// Testing instance, mocked `resource` should be injected here
@InjectMocks
@Resource
private TestedClass testedClass;


@Before
public void setUp() throws Exception {
// Initialize mocks created above
MockitoAnnotations.initMocks(this);
// Change behaviour of `resource`
when(resource.getSomething()).thenReturn("Foo");
}

可以使用 spring-rejecthttps://github.com/sgri/spring-reinject/使用模拟覆盖 bean 定义

我创建了 关于这个话题的博客文章,它还包含了 Github 存储库的链接和工作示例。

诀窍在于使用测试配置,在这里您可以使用假的 Spring bean 重写原始的 spring bean。您可以使用 @Primary@Profile注释来完成这个技巧。

Spring Boot 1.4引入了名为 @MockBean的测试注释。因此,现在 SpringBoot 本地支持对 Springbean 进行嘲笑和监视。

集成测试的另一种方法是定义一个新的 Configuration 类,并将其作为 @ContextConfiguration提供。在配置中,您将能够模拟您的 bean,并且您必须定义您在测试/s 流中使用的所有 bean 类型。 举个例子:

@RunWith(SpringRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class MockTest{
@Configuration
static class ContextConfiguration{
// ... you beans here used in test flow
@Bean
public MockMvc mockMvc() {
return MockMvcBuilders.standaloneSetup(/*you can declare your controller beans defines on top*/)
.addFilters(/*optionally filters*/).build();
}
//Defined a mocked bean
@Bean
public MyService myMockedService() {
return Mockito.mock(MyService.class);
}
}


@Autowired
private MockMvc mockMvc;


@Autowired
MyService myMockedService;


@Before
public void setup(){
//mock your methods from MyService bean
when(myMockedService.myMethod(/*params*/)).thenReturn(/*my answer*/);
}


@Test
public void test(){
//test your controller which trigger the method from MyService
MvcResult result = mockMvc.perform(get(CONTROLLER_URL)).andReturn();
// do your asserts to verify
}
}

对于 Junit5,你可以使用:

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class MytestClass {


@Mock
MyInjectedSevice myInjservice;


@InjectMock
MyService myservice;


}
import org.junit.Before;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;


import javax.annotation.Resource;


@Mock
private IMyInterface yInterface;


@InjectMocks
@Resource
ResourceDependant resourceDependant = new resourceDependant();




@Before
public void initMocksForInjection() throws Exception {
MockitoAnnotations.openMocks(this);
}