Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking a Private Variable that is Assumed to Exist

Tags:

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?

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.

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?

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();     ...   } } 
like image 606
Walls Avatar asked Oct 22 '13 14:10

Walls


People also ask

How do you mock a private method?

For Mockito, there is no direct support to mock private and static methods. In order to test private methods, you will need to refactor the code to change the access to protected (or package) and you will have to avoid static/final methods.

How do you private a mock variable in C#?

Make a protected getter for this private variable, and override it in testing subclass to return a mock object instead of the actual private variable. Create a protected factory method for creating ISnapshot object, and override it in testing subclass to return an instance of a mock object instead of the real one.

Can private variables be accessed?

We can access a private variable in a different class by putting that variable with in a Public method and calling that method from another class by creating object of that class. Example: using System; using System.


1 Answers

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).

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. 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.

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();   } } 
like image 107
Walls Avatar answered Sep 29 '22 17:09

Walls