【问题标题】:Mocking a class with Both Constructor and field injection使用构造函数和字段注入模拟类
【发布时间】:2021-08-18 20:16:24
【问题描述】:

我有一个类,我在其中添加了依赖项作为构造函数注入以及字段注入

@service
public class MyService {


    private final ClientOne clientOne;
    private final ClientTwo clientTwo;

    @Autowired
    private SpecialClient specialClient;

     public MyService(ClientOne clientOne,
                        ClientTwo clientTwo){
        this.clientOne=clientOne;
        this.clientTwo=clientTwo;
     }

当我编写测试用例时,如果我在 MyService 上使用 @InjectMock ,则在混合类型的依赖关系的情况下,Mockito 将使用 Constructor 来创建 Mock 并且我的 SpecialClient 将为空。 SpecialClient 一个内部依赖,所以我没有它的 setter,它也是私有的。

解决方法

现在我在上面的类中将 specialClient 包设为私有(在 specialClient 之前删除私有
然后在使用构造函数代码创建对象后在目标类中显式设置模拟,如下所示。 但实际上这应该是私有的,我仍然可以使用一些 ReflectionUtils 在 setup 方法中设置私有字段,但这也是另一个 Hack。

问题是
有没有办法 Mockito 为这种情况提供解决方案。初始化所有依赖项?

class MyServiceTest{
     
         MyService myService;
         
         @Mock
         ClientOne clientOne
         @Mock
         ClientTwo clientTwo
         @Mock
         SpecialClient specialClient
    
        @BeforeAll
        void setup(){
            myService = new MyService(clientOne,clientTwo);
            myService.specialClient=specialClient;
        }
    }

不,我不能将 specialClient 添加为构造函数 Arg,它实际上是一个 requestScope 依赖项。

【问题讨论】:

    标签: spring junit mockito autowired


    【解决方案1】:

    您不能使用@InjectMocks 通过构造函数注入和setter 注入来注入依赖项,@InjectMocks 清楚地记录了这一点:

    Mockito 将尝试仅按顺序通过构造函数注入、setter 注入或属性注入来注入模拟,如下所述。如果以下任一策略失败,则 Mockito 不会报告失败;即您必须自己提供依赖项。

    1. 构造函数注入;选择最大的构造函数,然后使用仅在测试中声明的模拟来解析参数。 如果使用构造函数成功创建对象,则 Mockito 不会尝试其他策略。 Mockito 已决定不破坏具有参数构造函数的对象。 注意:如果找不到参数,则传递 null。如果需要不可模拟的类型,则不会发生构造函数注入。在这些情况下,您必须自己满足依赖关系。

    您需要使用 Spring 特定的工具 - 让 Spring 创建 MyService bean 并将其自动装配到您的测试中:

    @ExtendWith(SpringExtension.class)
    @ContextConfiguration(classes = {MyService.class})
    public class MyServiceTest {
        @MockBean
        ClientOne clientOne;
    
        @MockBean
        ClientTwo clientTwo;
    
        @MockBean
        SpecialClient specialClient;
    
        @Autowired
        MyService myService;
    
    }
    

    【讨论】:

    • 谢谢,尽管我在问题中确实提到我不能使用 injectMock。
    • 您是否尝试运行您建议的代码?当我将所有@Mock 转换为@MockBean 并在MyService 类上使用@Autowired 时,我收到错误No qualifying bean of type '........MyService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} ...我确实将扩展名更改为@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = {MyService.class})
    猜你喜欢
    • 1970-01-01
    • 2018-11-02
    • 1970-01-01
    • 2013-11-13
    • 2017-04-05
    • 1970-01-01
    • 2018-03-06
    • 2017-01-29
    • 1970-01-01
    相关资源
    最近更新 更多