如何在生产中使用CDI测试类时注入模拟 [英] How to inject mocks while testing classes using CDI in production

查看:92
本文介绍了如何在生产中使用CDI测试类时注入模拟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Java SE环境中使用WELD-SE进行依赖项注入编程。因此,类的依赖关系如下所示:

I am programming in a Java SE environment using WELD-SE for dependency injection. Therefore dependencies of a class look something like this:

public class ProductionCodeClass {
    @Inject
    private DependencyClass dependency;
}

为此类编写单元测试时,我正在为<$创建一个模拟c $ c> DependencyClass ,由于我不想为我运行的每个测试都启动完整的CDI环境,因此我手动注入了模拟:

When writing a unit test for this class I am creating a mock for DependencyClass and as I don't want to start a complete CDI environment for every test I run, I "inject" the mock manually:

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 ()我已经使用测试工具编写了自己的课程:

The statically imported method setField() I have written myself in a class with tools I use in testing:

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项目,可以将其作为测试依赖项添加到我的项目中。

What I don't like about this solution is, that I need this helper over and over in any new project. I already packaged it as a Maven project I can add as a test dependency to my projects.

但是我缺少的某些其他公共库中没有准备好的东西吗? ?对我的一般做法有任何意见吗?

But isn't there something ready made in some other common library I am missing? Any comments on my way of doing this in general?

推荐答案

Mockito开箱即用地支持此操作:

Mockito supports this out of the box:

public class ProductionCodeClassTest {

    @Mock
    private DependencyClass dependency;

    @InjectMocks
    private ProductionCodeClass testedInstance;

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

}

@InjectMocks 批注将触发在测试类中模拟的类或接口的注入,在这种情况下, DependencyClass


Mockito尝试按类型进行注入(如果类型相同,则使用名称)。当注入失败时,Mockito不会抛出任何东西-您将必须手动满足依赖关系。

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(),但我更喜欢使用注释。

Here, I am also using the @Mock annotation instead of calling mock(). You could still use mock(), but I prefer using annotations.

作为补充,这里有一些反思可用的工具,它们支持您在 TestSupport 中实现的功能。一个这样的示例是 ReflectionTestUtils

As a side note, there are reflection tools available, which supports the functionality you implemented in TestSupport. One such example is ReflectionTestUtils.

也许最好还是使用构造函数注入

public class ProductionCodeClass {

    private final DependencyClass dependency;

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

这里的主要优点是很清楚该类依赖,并且如果不提供所有依赖关系就无法轻松构造它。此外,它允许注入的类为最终类。

The main advantage here is that it is clear what classes the class depends on, and that it cannot easily be constructed without providing all the dependencies. Also, it allows the injected class to be final.

这样做,不需要 @InjectMocks 。而是通过向构造函数提供模拟作为参数来创建类:

By doing this, @InjectMocks is not necessary. Instead, just create the class by providing the mock as a parameter to the constructor:

public class ProductionCodeClassTest {

    @Mock
    private DependencyClass dependency;

    private ProductionCodeClass testedInstance;

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

}

这篇关于如何在生产中使用CDI测试类时注入模拟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆