在服务测试中使用真实组件

Posted

技术标签:

【中文标题】在服务测试中使用真实组件【英文标题】:Use a real component in a service test 【发布时间】:2019-08-18 03:47:11 【问题描述】:

我正在测试具有自动装配帮助器组件的服务。该组件具有自动装配的 repo。

在我的测试中,我想使用那个组件助手,而不是模拟。我想为此模拟 repo。

但我无法让它工作。

我测试的服务:

@Service
public class ServiceImpl
    @Autowired
    private Helper helper;

具有自动装配 repo 的 Helper 类

@Component
public class Helper 
    @Autowired
    private Repository repo;

我的测试应该是这样的

@ExtendWith(MockitoExtension.class)
public class ServiceImplTest 

    ServiceImpl service;

    @Mock
    private Repository repoMock;

    @InjectMocks
    private Helper helper;


我想重构整个事情,但不幸的是,这是不可能的......

欢迎任何帮助。

【问题讨论】:

Repository 是类还是接口? Repository 是一个接口 【参考方案1】:

尝试为您的测试加载配置,优先考虑模拟存储库已测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class SomeTest 

    @Configuration
    static class ContextConfiguration      

        @Bean
        public Helper helper() 
            return new Helper();
        
        @Bean
        @Primary
        public Repository repoMock() 
            Repo repo = Mockito.mock(Repository.class);
            Mockito.when(/* Mock your repo */);
            return repo;
        
    

    @Autowired
    private Helper helper;

    @Test
    public void testMethod() 
        // Your test goes here
    

无论如何,请记住该字段自动装配is evil。尽快切换到构造函数依赖注入。

另请参阅:

https://***.com/a/39042441/1199132

【讨论】:

【参考方案2】:

我终于找到了解决办法,谢谢你的帮助。

@ExtendWith(MockitoExtension.class)
public class ServiceImplTest 

    @InjectMocks
    ServiceImpl service

    @Spy
    @InjectMocks
    private Helper helper;

    @Mock
    private Repository repoMock;

    @InjectMocks
    private Helper helper;

这样,mocked repo 被注入到 spy helper 中,而 helper 可以被注入到 service 中。 @Spy 对象实际上是实例化的,所以如果你不存根它的任何方法,你将得到一个“真实”的对象。

这里,mocked repo 被注入到 helper 中,而 helper 被注入到 service 中。

【讨论】:

【参考方案3】:

如果Repository 是一个接口(而不是具体类),您可以尝试以下操作:

@ExtendWith(MockitoExtension.class)
public class ServiceImplTest 

    @Spy
    @InjectMocks
    ServiceImpl service = new ServiceImpl();

    @Mock
    private Repository repoMock;

    @InjectMocks
    private Helper helper;

【讨论】:

问题依旧。在服务中使用 helper 时为 null,因为它没有正确注入(不是模拟) 实际上解决方案与您的解决方案很接近,但它是应该用@Spy注释的助手。【参考方案4】:

我更喜欢构造函数注入而不是字段注入。 (阅读更多here)

在这种情况下,你的类看起来像这样:

    @Component
    public class Helper 
        @Autowired
        public Helper(Repository repo) 
            this.repo = repo;
        
    

    @Service
    public class ServiceImpl
        @Autowired
        public ServiceImpl(Helper helper) 
            this.helper = helper;
        
    

通过这种方式,您可以使用模拟 Repository 对象轻松创建真正的 Helper 对象:

    ServiceImpl service;

    private Helper helper;

    @Mock
    private Repository repoMock;

    @BeforeEach
    void init() 
        helper = new Helper(repoMock);
        service = new ServiceImpl(helper);
    

【讨论】:

我也更喜欢它,但不幸的是,我无法修改我正在测试的类

以上是关于在服务测试中使用真实组件的主要内容,如果未能解决你的问题,请参考以下文章

组件 vs 集成 vs 功能测试

使用模拟服务时在业力测试中调用 OnInit() 后组件未定义

如何使用注入服务测试 Angular 1.6 组件?

使用 Karma 进行角度测试

使用 saga 对组件进行 React 测试

如何使用 Kotlin 在 Spring Test 类中注入服务组件?