Spring JUnit:如何在自动装配的组件中模拟自动装配的组件

时间:2013-10-10 15:07:05

标签: java spring junit dependency-injection

我有一个我想测试的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跑步者自动装配不同的实例吗?

6 个答案:

答案 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
 }
}