Java Spring JUnit:如何在autowired组件中模拟autowired组件
我有一个Spring组件要测试,这个组件有一个自动连接的属性,为了进行单元测试,我需要更改它。问题是,该类在post-construct方法中使用了自动连线组件,因此在实际使用之前,我无法替换它(即通过ReflectionTestUtils) 我该怎么做 这是我要测试的类:Java Spring JUnit:如何在autowired组件中模拟autowired组件,java,spring,junit,dependency-injection,Java,Spring,Junit,Dependency Injection,我有一个Spring组件要测试,这个组件有一个自动连接的属性,为了进行单元测试,我需要更改它。问题是,该类在post-construct方法中使用了自动连线组件,因此在实际使用之前,我无法替换它(即通过ReflectionTestUtils) 我该怎么做 这是我要测试的类: @Component public final class TestedClass{ @Autowired private Resource resource; @PostConstruct
@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 runner自动连接不同的实例吗?您可以提供一个新的testContext.xml,其中您定义的
@Autowired
bean属于测试所需的类型。您可以使用。具体而言,我不确定施工后,但这通常有效:
// 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 reinject用mock覆盖bean定义。它还包含指向Github存储库的链接以及工作示例
诀窍是使用测试配置,在这里您可以用伪Springbean覆盖原始Springbean。您可以使用@Primary
和@Profile
注释来实现此技巧 Spring Boot 1.4引入了名为的测试注释。因此,现在SpringBoot本机支持对SpringBean进行模拟和监视。集成测试中的另一种方法是定义一个新的配置类,并将其作为@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
}
}
谢谢这正是我所做和正在做的。我只是想知道是否有一种方法可以在不编写新上下文的情况下做到这一点(尽管我只导入了旧的上下文并覆盖了我需要的bean)@NeplatnyUdaj尝试使用@Qualifier(“myAlternateBean”)那么,它应该可以解决您的问题,这是一个误解。你的建议行得通。这不是我想要的。我会用它直到我找到别的东西。谢谢如果您在测试中使用自动连接,那么具有特定于测试的上下文是正常的,这样我就不用担心寻找更好的东西了。唯一的其他可能性是重写init(这意味着它不能是私有的)或手动连接bean以进行测试。@ph.如何在没有.xml文件的Spring Boot中执行此操作。我必须为测试创建一个配置文件吗?我已经尝试过了,但是PostConstruct
仍然在setUp()
方法之前执行。@NeplatnyUdaj,另一个机会是@BeforeClass
而不是@before
。不知道initMocks
如何处理这个问题。这也是我的想法,但是MockitoAnnotations.initMocks(Object o)
需要一个测试类的实例。或者对于新的TestUnit5,在测试类之前只需使用@ExtendWith(MockitoExtension.class)
。谢谢,这正是我需要的!取决于您使用的Spring版本-可能有不同的答案。参考: