java - 如何在生产中使用 CDI 测试类时注入(inject)模拟

标签 java unit-testing mockito cdi

我在 Java SE 环境中使用 WELD-SE 进行依赖注入(inject)编程。因此类的依赖看起来像这样:

public class ProductionCodeClass {
    @Inject
    private DependencyClass dependency;
}

在为此类编写单元测试时,我正在为 DependencyClass 创建一个模拟,因为我不想为我运行的每个测试启动一个完整的 CDI 环境,所以我“注入(inject)”了模拟手动:

import static TestSupport.setField;
import static org.mockito.Mockito.*;

public class ProductionCodeClassTest {
    @Before
    public void setUp() {
        mockedDependency = mock(DependencyClass.class);
        testedInstance = new ProductionCodeClass();
        setField(testedInstance, "dependency", mockedDependency);
    }
}

静态导入的方法setField() 我自己在一个类中编写了一个类,其中包含我在测试中使用的工具:

public class TestSupport {
    public static void setField(
                                final Object instance,
                                final String field,
                                final Object value) {
        try {
            for (Class classIterator = instance.getClass();
                 classIterator != null;
                 classIterator = classIterator.getSuperclass()) {
                try {
                    final Field declaredField =
                                classIterator.getDeclaredField(field);
                    declaredField.setAccessible(true);
                    declaredField.set(instance, value);
                    return;
                } catch (final NoSuchFieldException nsfe) {
                    // ignored, we'll try the parent
                }
            }

            throw new NoSuchFieldException(
                      String.format(
                          "Field '%s' not found in %s",
                          field,
                          instance));
        } catch (final RuntimeException re) {
            throw re;
        } catch (final Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

我不喜欢这个解决方案的地方在于,我在任何新项目中都一遍又一遍地需要这个助手。我已经将它打包为一个 Maven 项目,我可以将其作为测试依赖项添加到我的项目中。

但是我缺少的其他一些公共(public)库中是否有现成的东西?对我的一般做法有何评论?

最佳答案

Mockito 开箱即用:

public class ProductionCodeClassTest {

    @Mock
    private DependencyClass dependency;

    @InjectMocks
    private ProductionCodeClass testedInstance;

    @Before
    public void setUp() {
        testedInstance = new ProductionCodeClass();
        MockitoAnnotations.initMocks(this);
    }

}

@InjectMocks注释将触发注入(inject)测试类中模拟的类或接口(interface),在这种情况下 DependencyClass:

Mockito tries to inject by type (using name in case types are the same). Mockito does not throw anything when injection fails - you will have to satisfy the dependencies manually.

在这里,我也使用了@Mock注解,而不是调用mock()。您仍然可以使用 mock(),但我更喜欢使用注释。

作为旁注,有可用的反射工具,它支持您在 TestSupport 中实现的功能。一个这样的例子是 ReflectionTestUtils .


也许更好的方法是使用 constructor injection :

public class ProductionCodeClass {

    private final DependencyClass dependency;

    @Inject
    public ProductionCodeClass(DependencyClass dependency) {
        this.dependency = dependency;
    }
}

这里的主要优点是很清楚该类依赖于哪些类,并且在不提供所有依赖项的情况下无法轻易构建它。此外,它允许注入(inject)的类是最终类。

通过这样做,@InjectMocks 就不是必需的了。相反,只需通过将模拟作为参数提供给构造函数来创建类:

public class ProductionCodeClassTest {

    @Mock
    private DependencyClass dependency;

    private ProductionCodeClass testedInstance;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        testedInstance = new ProductionCodeClass(dependency);
    }

}

关于java - 如何在生产中使用 CDI 测试类时注入(inject)模拟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32422930/

相关文章:

java - 在android中使用onScanResult获取两个BLE设备

java - 如何在 Eclipse 中使用引用库中的类

c# - 用于 Web API 单元测试的模拟请求对象

java - Powermock withArguments 调用变量输入

java - Mockito 测试用例忽略注释

java - Mockito @InjectMocks 不适用于相同类型的字段

java - Intellij Idea 中类型迁移的用例是什么?

java - 不可变对象(immutable对象)的 null 和默认行为

python - 测试 Tornado 应用程序的 4xx 状态代码

unit-testing - 单元测试中逐步断言的值(value)