Java 使用 Mockito 将模拟对象注入到要测试的对象中,声明为测试中的字段不起作用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19580197/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 18:30:12  来源:igfitidea点击:

Injection of a mock object into an object to be tested declared as a field in the test does not work using Mockito?

javamockito

提问by Phoenix

I have a class and I am injecting a proxy into my service.

我有一堂课,我正在向我的服务中注入一个代理。

Service service
{
    private ServiceProxy proxy;
    public Service(ServiceProxy proxy)
    {
        this.proxy = proxy; 
    }
}

The test for it is:

对它的测试是:

ServiceTest
{
    @Mock
    ServiceProxy mockProxy;
    Service service = new Service(mockProxy);
}

If I initialize my class like this I always get a NPEwhen I want to use the service object. Why does Mockitodo this? What is an easy way around this instead of declaring it in each and every test?

如果我像这样初始化我的类,NPE当我想使用服务对象时,我总是会得到一个。为什么这样Mockito做?有什么简单的方法可以解决这个问题而不是在每个测试中都声明它?

采纳答案by macias

Provided you are using Mockito version 1.9.0 or later, the best way to achieve what you want is like this:

如果您使用的是 Mockito 1.9.0 或更高版本,那么实现您想要的最佳方式是这样的:

@RunWith(MockitoJUnitRunner.class)
public class ServiceTest {

    @Mock
    private ServiceProxy proxy;

    @InjectMocks
    private Service service;

    @Test
    public void test() {
        assertNotNull(service);
        assertNotNull(proxy);
    }
}

First thing is the @RunWith(MockitoJUnitRunner.class)declaration which will cause @Mock and @InjectMocks annotation to work automatically without any explicit initialization. The second thing is that starting with Mockito 1.9.0 @InjectMocks annotation can use the Constructor injectionmechanism which is the best option for your Serviceclass.

首先是@RunWith(MockitoJUnitRunner.class)声明将导致 @Mock 和 @InjectMocks 注释自动工作而无需任何显式初始化。第二件事是从 Mockito 1.9.0 @InjectMocks 注释开始可以使用构造函数注入机制,这是您的服务类的最佳选择。

Other options for @InjectMocks are Setter injectionand Field injection(see docsBTW) but you'd need a no argument constructor to use them.

@InjectMocks 的其他选项是Setter 注入Field 注入(请参阅文档BTW),但您需要一个无参数构造函数来使用它们。

So summarizing - your code cannot work because:

总结一下 - 您的代码无法工作,因为:

  • you are not using the MockitoJUnitRunner nor MockitoAnnotations.initMocks(this) so @Mock annotation takes no effect
  • even if above were satisfied your example would fail because mockProxywould be initialized afterthe test is constructed and your serviceis tried to be initialized during the test class construction, hence it receives null mockProxyreference.
  • 您没有使用 MockitoJUnitRunner 或 MockitoAnnotations.initMocks(this) 所以@Mock 注释不起作用
  • 即使满足上述要求,您的示例也会失败,因为构建测试会初始化mockProxy,并且在测试类构建期间尝试初始化您的服务,因此它收到 null mockProxy引用。

If for some reason you don't want to use @InjectMocks, the only way is to construct your Serviceobject within the test method body or within the @Before annotated setUp method.

如果由于某种原因您不想使用@InjectMocks,唯一的方法是在测试方法主体或@Before 注释的setUp 方法中构造您的服务对象。

回答by Debojit Saikia

Write your test class as this, which will initialize Servicewith a mock of ServiceProxy:

将您的测试类编写为这样,它将Service使用以下模拟进行初始化ServiceProxy

class ServiceTest
{
@Mock
ServiceProxy mockProxy;

//This will inject the "ServiceProxy" mock into your "Service" instance.
@InjectMocks
Service service = new Service(mockProxy);

@Before
public void init() {
//This will initialize the annotated mocks 
MockitoAnnotations.initMocks(this);
}

@Test
public void test() {
... 
}
}