SpringJUnit:如何在自动布线组件中模拟自动布线组件

ct2axkht  于 2022-11-11  发布在  Spring
关注(0)|答案(8)|浏览(145)

我想测试一个Spring组件,这个组件有一个autowired属性,为了进行单元测试,我需要修改这个属性。问题是,这个类在构造后方法中使用了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方法之前,是否有某种方法可以将资源替换为其他资源?比如告诉SpringJUnit运行器自动连接不同的示例?

ep6jt1vc

ep6jt1vc1#

您可以使用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");   
}
6tqwzwtp

6tqwzwtp2#

SpringBoot1.4 引入 了 名 为 @MockBean 的 测试 注解 , 所以 现在 SpringBoot 本身 就 支持 对 Springbeans 的 模拟 和 监视 。

5rgfhyps

5rgfhyps3#

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

gajydyqb

gajydyqb4#

我创建了blog post on the topic。它还包含了到Github仓库的链接和工作示例。
技巧是使用测试配置,在这里你用一个假的spring bean覆盖原来的spring bean。

kse8i1jr

kse8i1jr5#

您可以使用spring-reinject https://github.com/sgri/spring-reinject/通过模拟来覆盖bean定义

5cg8jx4n

5cg8jx4n6#

集成测试中的另一种方法是定义一个新的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
 }
}
knpiaxh1

knpiaxh17#

对于Junit5,您可以使用以下命令进行模拟:

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

@Mock
MyInjectedSevice myInjservice;

@InjectMock
MyService myservice;

}
w8ntj3qf

w8ntj3qf8#

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);
    }

相关问题