我有一个我想测试的Spring组件,这个组件有一个autowired属性,我需要更改它以进行单元测试。问题是,该类在后构造方法中使用自动装配组件,因此在实际使用之前我无法替换它(即通过ReflectionTestUtils)。
我该怎么做?
这是我要测试的课程:
@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"));
}
}
在调用postconstruct方法之前,有没有办法用其他东西替换资源?想告诉Spring JUnit跑步者自动装配不同的实例吗?
答案 0 :(得分:50)
您可以使用Mockito。我不确定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");
}
答案 1 :(得分:18)
Spring Boot 1.4引入了名为@MockBean
的测试注释。因此,Spring Boot本身支持对Spring bean进行模拟和监视。
答案 2 :(得分:9)
您可以提供一个新的testContext.xml,其中您定义的@Autowired
bean是您测试所需的类型。
答案 3 :(得分:6)
您可以使用spring-reinject https://github.com/sgri/spring-reinject/
覆盖mocks的bean定义答案 4 :(得分:6)
我创建了blog post on the topic。它还包含带有工作示例的Github存储库的链接。
诀窍是使用测试配置,你可以用假的Spring覆盖原始的spring bean。您可以使用@Primary
和@Profile
注释来完成此操作。
答案 5 :(得分:3)
集成测试中的另一种方法是定义一个新的Configuration类,并将其作为您的@ContextConfiguration
提供。进入配置后,您将能够模拟您的bean,并且还必须定义在测试流程中使用的所有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
}
}