【问题标题】:InjectMocks is wrongly injecting the same Mock into 2 different fields of similar type despite creating 2 different mocks尽管创建了 2 个不同的模拟,但 InjectMocks 错误地将相同的模拟注入到 2 个相似类型的不同字段中
【发布时间】:2021-01-01 11:51:23
【问题描述】:

我有一个类有 2 个类似类型的字段。我嘲笑过他们俩。但是当我使用 InjectMocks 时,注入模拟错误地将单个模拟注入到这两个字段中。

这是示例代码类:


import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;

import java.util.Set;
import java.util.function.Consumer;

@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class TestClass {

    private final Consumer<Set<Integer>> intConsumer;

    private final Consumer<Set<String>> stringConsumer;

    void PrintClass(){
        System.out.println("intConsumers: " + intConsumer);
        System.out.println("stringConsumers: " + stringConsumer);
    }
}

这里是测试类:


import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import java.util.Set;
import java.util.function.Consumer;

@RunWith(MockitoJUnitRunner.class)
public class TestClassTest {

    @Mock private Consumer<Set<Integer>> intConsumer;
    @Mock private Consumer<Set<String>> stringConsumer;
    @InjectMocks private TestClass testClass;

    @Test
    public void testPrint(){
        testClass.PrintClass();
    }


}

这是我运行测试时的输出:testPrint() - intConsumer 被注入到 intConsumer 和 stringConsumer 中。

intConsumers: intConsumer
stringConsumers: intConsumer



Process finished with exit code 0

我正在使用 Maven。

<dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>2.7.19</version>
</dependency>

我创建了这个私有构造函数,专门用于使用 InjectMocks 进行测试。我不想让它公开/包私有,所以我不能使用字段注入。我也不想使用公共设置器公开这些字段。另外,我不想让我的字段成为非最终字段。

我已经尝试将 mockito-version 升级到 3.5.10,但它仍然存在这个错误。 我也尝试过使我的字段最终化并使用 setter - 然后 Injection 工作正常 - 但我不想公开我的 setter。 我也尝试过使用构造函数注入来命名模拟 @Mock(name = "mock"),但效果不佳。

我在这里遗漏了什么吗?有没有办法让它与私有构造函数注入一起工作?

【问题讨论】:

    标签: java maven junit mockito inject


    【解决方案1】:

    这是 Mockito 中的一个开放错误。

    据我所见,PropertyAndSetterInjection 将泛型类型和@Mock 的名称属性考虑在内,因此它可以按预期进行字段注入。但它不适用于构造函数,因为 ConstructorInjection 仅使用 SimpleArgumentResolver,这很好......非常简单,并且没有像属性注入器那样的任何 MockCandidateFilter。

    通常,您会:

    • 删除@InjectMocks 并在测试的设置方法中构造TestClass 实例。恕我直言,这是一种侵入性较小的方法。
    • 或者,如上所述,字段和设置器注入工作。

    这两种方法都不适用于您的约束(私有构造函数、无设置器、最终字段)。

    在这种情况下,您可以借助反射来构建实例:

    @Before
    public void setUp() throws IllegalAccessException, 
            InvocationTargetException, 
            InstantiationException,
            NoSuchMethodException {
        final Constructor<TestClass> constructor = TestClass.class.getDeclaredConstructor(Consumer.class, Consumer.class);
        constructor.setAccessible(true);
        testClass = constructor.newInstance(intConsumer, stringConsumer);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-19
      • 1970-01-01
      • 2020-03-18
      • 1970-01-01
      • 2011-06-25
      • 2019-02-05
      • 1970-01-01
      • 2015-07-09
      相关资源
      最近更新 更多