Java Spring JUnit:如何在自动装配组件中模拟自动装配组件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19299513/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring JUnit: How to Mock autowired component in autowired component
提问by NeplatnyUdaj
I've got a Spring component I'd like to test and this component has an autowired attribute which I need to change for the purpose of unit testing. The problem is, that the class uses the autowired component inside the post-construct method so I'm not able to replace it(i.e. via ReflectionTestUtils) before it's actually used.
我有一个想要测试的 Spring 组件,这个组件有一个自动装配的属性,为了单元测试的目的,我需要更改它。问题是,该类在 post-construct 方法中使用自动装配的组件,因此我无法在实际使用之前替换它(即通过 ReflectionTestUtils)。
How should I do that?
我该怎么做?
This is the class I want to test:
这是我要测试的课程:
@Component
public final class TestedClass{
@Autowired
private Resource resource;
@PostConstruct
private void init(){
//I need this to return different result
resource.getSomething();
}
}
And this is the base of a test case:
这是测试用例的基础:
@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"));
}
}
Is there some way to replace the resource with something else before the postconstruct method is invoked? Like to tell Spring JUnit runner to autowire different instance?
在调用 postconstruct 方法之前,有什么方法可以用其他东西替换资源吗?喜欢告诉 Spring JUnit runner 自动装配不同的实例吗?
采纳答案by phury
You can provide a new testContext.xml in which the @Autowired
bean you define is of the type you need for your test.
您可以提供一个新的 testContext.xml,其中@Autowired
您定义的bean 是您测试所需的类型。
回答by Anna Zubenko
You could use Mockito. I am not sure with PostConstruct
specifically, but this generally works:
你可以使用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");
}
回答by Sergey Grigoriev
You can override bean definitions with mocks with spring-reinject https://github.com/sgri/spring-reinject/
您可以使用 spring-reinject https://github.com/sgri/spring-reinject/用模拟覆盖 bean 定义
回答by luboskrnac
I created blog post on the topic. It contains also link to Github repository with working example.
我创建了关于该主题的博客文章。它还包含带有工作示例的 Github 存储库的链接。
The trick is using test configuration, where you override original spring bean with fake one. You can use @Primary
and @Profile
annotations for this trick.
诀窍是使用测试配置,在其中用假的 spring bean 覆盖原始 spring bean。您可以使用@Primary
和@Profile
注解这一招。
回答by luboskrnac
回答by Rzv Razvan
Another approach in integration testing is to define a new Configuration class and provide it as your @ContextConfiguration
. Into the configuration you will be able to mock your beans and also you must define all types of beans which you are using in test/s flow.
To provide an example :
集成测试的另一种方法是定义一个新的 Configuration 类并将其作为您的@ContextConfiguration
. 在配置中,您将能够模拟您的 bean,并且您还必须定义您在 test/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
}
}