模拟假定存在的私有变量 [英] Mocking a Private Variable that is Assumed to Exist

查看:161
本文介绍了模拟假定存在的私有变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果没有在您正在测试的类中创建/初始化模拟对象,它是如何在运行时获取模拟对象的,它不是静态的(单例模式),或者您没有某种类型的测试构造函数可以挂钩到?

How can you get a mock object in at runtime when it is not created/initialized in the class you are testing, it is not static (singleton pattern), or you don't have some sort of test constructor to hook into?

在我正在编写一些单元测试的类中,我遇到了一个我尚未遇到/解决过的场景。我有一个JMS资源(一个 QueueConnectionFactory 供参考,但它没关系),这是我正在测试的类的私有变量。由于它具有 javax.annotation.Resource 注释,因此在运行时它被认为是可用的。在测试期间,它不是,这就需要模拟这个对象。

In a class that I am writing some unit testing for, I have come across a scenario I haven't encountered/solved yet. I have a JMS resource (a QueueConnectionFactory for reference, but it shouldn't matter), that is a private variable of the class I am testing. Since it has the javax.annotation.Resource annotation, at runtime it is assumed to be available. During testing, it is not, which creates the need for mocking this object.

它不是一个静态类,并且没有以静态方式使用,如果它是我可以使用我遇到的各种静态模拟方法轻松模拟。由于资源永远不会在本地创建(在构造函数中或甚至在测试构造函数中),因此我无法传入Mock对象,因此在测试的运行时,使用mock而不是实际对象。如何模拟此资源,以便在测试执行时,它将用于代替我正在测试的类中的私有 @Resource 对象?

It is not a static class and is not being used in a static way, if it was I could easily mock using the various static mocking methods I have run into. Since the resource is never created locally (in a constructor or even in a test constructor), I have no way of passing in a Mock object so that at runtime of the test, the mock is used instead of the actual object. How can I mock this Resource so that when the test executes, it will be used in place of the private @Resource object in the class I am testing?

作为参考,代码在 QueueConnectionFactory 上调用 createConnection()抛出空指针异常,因为Factory尚未初始化/模拟。

For reference, the code is calling createConnection() on the QueueConnectionFactory which is throwing a null pointer exception since the Factory has not been initialized/mocked.

@Stateless
public class Example{
  @Resource(name = "jms/exampleQCF")
  private QueueConnectionFactory queueFactory;

  ...

  public void testMe(){
    Connection connection = queueFactory.createConnection();
    ...
  }
}


推荐答案

经过更多的狩猎并查看Mockito / Powermock提供的所有选项之后,我找到了解决方案(如果其他人遇到同样的问题,我将分享这些解决方案)。

After a lot more hunting around and looking at all the options Mockito/Powermock had to offer, I found the solution (which I will share in case others run into this same issue).

当您拥有从未初始化的私有成员变量(并假设在其他地方创建)时,您可以使用 @InjectMocks 注释注入你想要的模拟你正在测试的类。

When you have private member variables that are never initialized (and just assumed created in other places), you can use the @InjectMocks annotation to "inject" Mocks you want into your class you are testing.


  1. 在你正在测试的类的测试类中添加一个变量,给它注释 @InjectMocks (org.Mockito.InjectMocks)。

  2. 使用 @Mock 注释以设置要注入的模拟。使用 @Mock(name =privateVariableNameHere) name属性将Mock对象映射到您正在测试的类中的私有变量。

  3. 在设置功能中或在调用类之前,初始化模拟。我找到的最简单的方法是使用带有 @Before 注释的setup方法。然后在里面调用 MockitoAnnotations.initMocks(this); 使用 @Mock 注释快速初始化任何内容。

  4. 在测试方法中定义您的Mock功能(在调用您正在测试的方法之前)。

  5. 使用 @InjectMock object,调用你正在测试的方法......模拟应该被挂钩并按照前面步骤中的定义工作。

  1. Add a variable in your test class for the class you are testing, and give it the annotation @InjectMocks (org.Mockito.InjectMocks).
  2. Use @Mock annotations to setup the mocks you want to inject. Use the @Mock (name = "privateVariableNameHere") name property to map the Mock object to the private variable inside your class you are testing.
  3. In either a setup function or before you call your class, initialize the mocks. The easiest way I have found is to use a "setup" method with the @Before annotation. Then inside there call MockitoAnnotations.initMocks(this); to quickly initialize anything with the @Mock annotation.
  4. Define your Mock functionality in your test method (before calling the method you are testing).
  5. Using the @InjectMock object, call your method you are testing... the mocks SHOULD be hooked in and working as defined in the earlier steps.

因此,对于我上面使用的示例类,test / mock的代码将 Connection 作为模拟返回,您可以执行任何操作。根据我的问题上面的例子,这就是代码的样子:

So for the example class I use above, the code to test/mock would have Connection returned as a mock which you can do whatever with. Based on the example above in my question, this is what the code would look like:

@RunWith(PowerMockRunner.class)
@PrepareForTest({/* Static Classes I am Mocking */})
public class ExampleTest {
  @Mock (name = "queueFactory") //same name as private var.
  QueueConnectionFactory queueFactoryMock;
  @Mock
  Connection connectionMock; //the object we want returned
  @InjectMocks
  Example exampleTester; //the class to test

  @Before
  public void setup(){
    MockitoAnnotations.initMocks(this); // initialize all the @Mock objects
    // Setup other Static Mocks
  }

  @Test
  public void testTestMe(){
    //Mock your objects like other "normally" mocked objects
    PowerMockito.when(queueFactoryMock.createConnection()).thenReturn(connectionMock);
    //...Mock ConnectionMock functionality...
    exampleTester.testMe();
  }
}

这篇关于模拟假定存在的私有变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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