Preface:
This question and answer is intended as a canonical answer to
the majority of questions that arise due to misuse of Mockito or
misunderstanding how Mockito works and interacts with unit tests
written in the Java language.
I have implemented a class which should be unit tested. Note that the code shown here is only a dummy implementation and Random is for illustrative purposes. Real code would use a real dependency, such as another service or repository.
public class MyClass {
public String doWork() {
final Random random = new Random(); // the `Random` class will be mocked in the test
return Integer.toString(random.nextInt());
}
}
I want to use Mockito for mocking other classes and have written a really simple JUnit test. However, my class is not using the mock in the test:
public class MyTest {
#Test
public void test() {
Mockito.mock(Random.class);
final MyClass obj = new MyClass();
Assertions.assertEquals("0", obj.doWork()); // JUnit 5
// Assert.assertEquals("0", obj.doWork()); // JUnit 4
// this fails, because the `Random` mock is not used :(
}
}
Even running the test with the MockitoJUnitRunner (JUnit 4) or extending with MockitoExtension (JUnit 5) and annotating with #Mock does not help; the real implementation is still used:
#ExtendWith(MockitoExtension.class) // JUnit 5
// #RunWith(MockitoJUnitRunner.class) // JUnit 4
public class MyTest {
#Mock
private Random random;
#Test
public void test() {
final MyClass obj = new MyClass();
Assertions.assertEquals("0", obj.doWork()); // JUnit 5
// Assert.assertEquals("0", obj.doWork()); // JUnit 4
// `Random` mock is still not used :((
}
}
Why is the mocked class not used, even though the Mockito methods are called before my class is tested or the test is executed with the Mockito extension/runner?
Other variants of this question include but are not limited to:
My mocks return null / My stubs return null
NullPointerException when using Mockito
My mocks are null in test
My mocks don't return the expected value / My stubs do not return the expected value
Mockito thenReturn not honored / Mockito thenAnswer not honored
#InjectMocks not working
#Mock not working
Mockito.mock not working
My class is not using mocks / My class is not using stubs
My tests still call or execute the real implementation of a mocked/stubbed class
TLDR: Two or more distinct instances of your mock exist. Your test is using one instance and your class under test is using another instance. Or you are not using mocks at all in your class because you new up objects inside the class.
Problem Overview (Classes vs Instances)
Mocks are instances (that's why they are also called "mock objects"). Calling Mockito.mock on a class will return a mock object for this class. It must be assigned to a variable which can then be passed to the relevant methods or injected as dependency into other classes. It does not modify the class itself! Think about it: if that were true, then all instances of the class would somehow, magically, be converted to mocks. That would make it impossible to mock classes of which multiple instances are used or classes from the JDK, such as List or Map (which shouldn't be mocked in the first place, but that's a different story).
The same holds true for #Mock annotation with the Mockito extension/runner: a new instance of a mock object is created, which is then assigned to the field (or parameter) annotated with #Mock. This mock object still needs to be passed to the correct methods or injected as dependency.
Another way to avoid this confusion: new in Java will always allocate memory for an object and will initialize this new instance of the real class. It is impossible to override the behavior of new. Not even clever frameworks such as Mockito can do it.
Solution
»But how can I mock my class?« you will ask. Change the design of your classes to be testable! Every time you decide to use new, you commit yourself to an instance of this exact type. Multiple options exist, depending on your concrete use case and requirements, including but not limited to:
If you can change the signature/interface of the method, pass the (mock) instance as method parameter. This requires the instance to be available in all call sites, which might not always be feasible.
If you cannot change the signature of the method, inject the dependency in your constructor and store it in a field to be later used by methods.
Sometimes, the instance must only be created when the method is called and not prior to it. In that case, you can introduce another level of indirection and use something known as the abstract factory pattern. The factory object will then create and return the instance of your dependency. Multiple implementations of the factory can exist: one which returns the real dependency and another one which returns a test double, such as a mock.
Below you will find sample implementations for each of the options (with and without Mockito runner/extension):
Changing Method Signature
public class MyClass {
public String doWork(final Random random) {
return Integer.toString(random.nextInt());
}
}
public class MyTest {
#Test
public void test() {
final Random mockedRandom = Mockito.mock(Random.class);
final MyClass obj = new MyClass();
Assertions.assertEquals("0", obj.doWork(mockedRandom)); // JUnit 5
// Assert.assertEquals("0", obj.doWork(mockedRandom)); // JUnit 4
}
}
#ExtendWith(MockitoExtension.class) // JUnit 5
// #RunWith(MockitoJUnitRunner.class) // JUnit 4
public class MyTestAnnotated {
#Mock
private Random random;
#Test
public void test() {
final MyClass obj = new MyClass();
Assertions.assertEquals("0", obj.doWork(random)); // JUnit 5
// Assert.assertEquals("0", obj.doWork(random)); // JUnit 4
}
}
Constructor Dependency Injection
public class MyClass {
private final Random random;
public MyClass(final Random random) {
this.random = random;
}
// optional: make it easy to create "production" instances (although I wouldn't recommend this)
public MyClass() {
this(new Random());
}
public String doWork() {
return Integer.toString(random.nextInt());
}
}
public class MyTest {
#Test
public void test() {
final Random mockedRandom = Mockito.mock(Random.class);
final MyClass obj = new MyClass(mockedRandom);
// or just obj = new MyClass(Mockito.mock(Random.class));
Assertions.assertEquals("0", obj.doWork()); // JUnit 5
// Assert.assertEquals("0", obj.doWork()); // JUnit 4
}
}
#ExtendWith(MockitoExtension.class) // JUnit 5
// #RunWith(MockitoJUnitRunner.class) // JUnit 4
public class MyTestAnnotated {
#Mock
private Random random;
#Test
public void test() {
final MyClass obj = new MyClass(random);
Assertions.assertEquals("0", obj.doWork()); // JUnit 5
// Assert.assertEquals("0", obj.doWork()); // JUnit 4
}
}
Delayed Construction via Factory
Depending on the number of constructor arguments of your dependency and need for expressive code, one could use existing interfaces from the JDK (Supplier, Function, BiFunction) or introduce a custom factory interface (annotated with #FunctionInterface if it only has a single method).
The following code will opt for a custom interface, but would work just fine with Supplier<Random>.
#FunctionalInterface
public interface RandomFactory {
Random newRandom();
}
public class MyClass {
private final RandomFactory randomFactory;
public MyClass(final RandomFactory randomFactory) {
this.randomFactory = randomFactory;
}
// optional: make it easy to create "production" instances (again: I wouldn't recommend this)
public MyClass() {
this(Random::new);
}
public String doWork() {
return Integer.toString(randomFactory.newRandom().nextInt());
}
}
public class MyTest {
#Test
public void test() {
final RandomFactory randomFactory = () -> Mockito.mock(Random.class);
final MyClass obj = new MyClass(randomFactory);
Assertions.assertEquals("0", obj.doWork()); // JUnit 5
// Assert.assertEquals("0", obj.doWork()); // JUnit 4
}
}
#ExtendWith(MockitoExtension.class) // JUnit 5
// #RunWith(MockitoJUnitRunner.class) // JUnit 4
public class MyTestAnnotated {
#Mock
private RandomFactory randomFactory;
#Test
public void test() {
// this is really awkward; it is usually simpler to use a lambda and create the mock manually
Mockito.when(randomFactory.newRandom()).thenAnswer(a -> Mockito.mock(Random.class));
final MyClass obj = new MyClass(randomFactory);
Assertions.assertEquals("0", obj.doWork()); // JUnit 5
// Assert.assertEquals("0", obj.doWork()); // JUnit 4
}
}
Corollary: (Mis-)using #InjectMocks
But I'm using #InjectMocks and verified with the debugger that I have mocks inside my class under test. Yet, the mock methods I set up with Mockito.mock and Mockito.when are never called! (In other words: "I get an NPE", "my collections are empty", "default values are returned", etc.)
— a confused developer, ca. 2022
Expressed in code, the above quote would look something like this:
#ExtendWith(MockitoExtension.class) // JUnit 5
// #RunWith(MockitoJUnitRunner.class) // JUnit 4
public class MyTestAnnotated {
#Mock
private Random random;
#InjectMocks
private MyClass obj;
#Test
public void test() {
random = Mockito.mock(Random.class);
Mockito.when(random.nextInt()).thenReturn(42);
Assertions.assertEquals("42", obj.doWork()); // JUnit 5
// Assert.assertEquals("42", obj.doWork()); // JUnit 4
}
}
The problem with the code above is the first line in the test() method: it creates and assigns a new mock instance to the field, effectively overwriting the existing value. But #InjectMocks injects the original value into the class under test (obj). The instance created with Mockito.mock only exists in the test, not in the classes under test.
The order of operations here is:
All #Mock-annotated fields get assigned a new mock object.
The #InjectMocks-annotated field gets injected references to the mock object(s) from step 1.
The reference in the test class is overwritten with a different reference to the new mock object (created via Mockito.mock). The original reference is lost and no longer available in the test class.
The class under test (obj) still holds a reference to the initial mock instance and uses that. The test only has a reference to the new mock instance.
This basically boils down to Is Java "pass-by-reference" or "pass-by-value"?.
You can verify this with a debugger. Set a breakpoint and then compare the object addresses/ids of the mock fields in the test class and in the class under test. You will notice that those are two different, unrelated object instance.
The solution? Don't overwrite the reference, but set up the mock instance created via the annotation. Simply get rid of the re-assignment with Mockito.mock:
#ExtendWith(MockitoExtension.class) // JUnit 5
// #RunWith(MockitoJUnitRunner.class) // JUnit 4
public class MyTestAnnotated {
#Mock
private Random random;
#InjectMocks
private MyClass obj;
#Test
public void test() {
// this.random must not be re-assigned!
Mockito.when(random.nextInt()).thenReturn(42);
Assertions.assertEquals("42", obj.doWork()); // JUnit 5
// Assert.assertEquals("42", obj.doWork()); // JUnit 4
}
}
Corollary: Object life cycles and magic framework annotations
I followed your advice and use dependency injection to manually pass the mock into my service. It's still not working and my test fails with null pointer exceptions, sometimes even before a single test method actually runs. You lied, bruh!
— another confused developer, late 2022
The code would likely look something like:
#ExtendWith(MockitoExtension.class) // JUnit 5
// #RunWith(MockitoJUnitRunner.class) // JUnit 4
public class MyTestAnnotated {
#Mock
private Random random;
private final MyClass obj = new MyClass(random);
#Test
public void test() {
Mockito.when(random.nextInt()).thenReturn(42);
Assertions.assertEquals("42", obj.doWork()); // JUnit 5
// Assert.assertEquals("42", obj.doWork()); // JUnit 4
}
}
This is very similar to the first corollary and boils down to object life cycles and references vs values. The steps happening in the code above are as follows:
A new instance of MyTestAnnotated is created by the testing framework (e.g. new MyTestAnnotated()).
All constructors and field initializers are executed. There are no constructors here, but a field initializer: private MyClass obj = new MyClass(random);. At this point in time, the random field still has its default value null → the obj field is assigned new MyClass(null).
All #Mock-annotated fields get assigned a new mock object. This does not update the value in MyService obj, because it got passed null initially, not a reference to the mock.
Depending on your MyService implementation, this might already fail when creating an instance of the test class (MyService might perform parameter validation of its dependencies in the constructor); or it might only fail when executing a test method (because the dependency is null).
The solution? Familiarize yourself with object life cycles, field initializer order, and the point in time when mock frameworks can/will inject their mocks and update references (and which references are updated). Try to avoid mixing "magic" framework annotations with manual setup. Either create everything manually (mocks, service), or move the initialization to the methods annotated with #Before (JUnit 4) or #BeforeEach (JUnit 5).
#ExtendWith(MockitoExtension.class) // JUnit 5
// #RunWith(MockitoJUnitRunner.class) // JUnit 4
public class MyTestAnnotated {
#Mock
private Random random;
private MyClass obj;
#BeforeEach // JUnit 5
// #Before // JUnit 4
public void setup() {
obj = new MyClass(random);
}
#Test
public void test() {
Mockito.when(random.nextInt()).thenReturn(42);
Assertions.assertEquals("42", obj.doWork()); // JUnit 5
// Assert.assertEquals("42", obj.doWork()); // JUnit 4
}
}
Alternatively, set up everything manually without annotations which require a custom runner/extension:
public class MyTest {
private Random random;
private MyClass obj;
#BeforeEach // JUnit 5
// #Before // JUnit 4
public void setup() {
random = Mockito.mock(random);
obj = new MyClass(random);
}
#Test
public void test() {
Mockito.when(random.nextInt()).thenReturn(42);
Assertions.assertEquals("42", obj.doWork()); // JUnit 5
// Assert.assertEquals("42", obj.doWork()); // JUnit 4
}
}
References
Is Java "pass-by-reference" or "pass-by-value"?
Initialising mock objects - Mockito
Difference between #Mock and #InjectMocks
Related
I would like to create some Junit test using the annotation #Mock and MockitoExtension.
Something like this:
#ExtendWith(MockitoExtension.class)
public class Test {
#Mock
MyObject mock;
#Test
public void test1() {
..
}
#Test
public void test2() {
..
}
How can I tell to MockitoExtension that it has to create the mock before each test execution to isolate them?
I would like to avoid that the first executed test defining a behavior for the mock with when(mock.doSomething()).then(returnSomething()) will not influence the other tests by resetting the mock)
It's not just Mockito that is reinitialized, it's standard JUnit behavior. A new instance of your Test class is created for each method. So this creates isolation between each test for anything you set up as instance members, including Mockito instances.
You can imagine your test is run like this:
Test instance1 = new Test();
instance1.test1();
Test instance2 = new Test();
instance2.test2();
You can set behavior for each instance using #BeforeEach:
#BeforeEach
void setUp() {
// this runs for every test method on a brand new scope
}
notice how it is an instance method.
If you do want "global" behavior, you use static methods and variables instead. The corresponding annotations are #BeforeAll/#AfterAll which must be applied to static methods and runs once each for the whole class.
I am trying to create a unit test for the following method that calls another private method:
public CommandDTO create(final LabelRequest request) {
return saveLabel(new Label(), request);
}
private CommandDTO saveLabel(final Label label, final LabelRequest request) {
label.setName(request.getName());
final Label saved = labelRepository.saveAndFlush(label);
return CommandDTO.builder().uuid(saved.getUuid()).build();
}
It returns "nullpointer exception for the saved parameter as I did not mock in in my test.
Here is the Unit Test. I added 2 question as comment (Q1 and Q2). Could you please clarify me what is wrong?
#RunWith(MockitoJUnitRunner.class)
public class LabelServiceImplTest {
#Mock
private LabelRepository labelRepository;
#InjectMocks
private LabelServiceImpl labelService;
#Captor
ArgumentCaptor<Label> labelCaptor;
#Test
public void test_create {
// Q1: I am not sure if the following parts are needed
final LabelRequest request = new LabelRequest();
request.setName("Label Name");
final Label label = new Label();
label.setName(request.getName());
// Q2: I think there is no need to mock saveAndFlush method.
// But in this scene it returns "nullpointer exception"
when(labelRepository.saveAndFlush(any())).thenReturn(label);
CommandDTO result = labelService.create(request);
Mockito.verify(labelRepository).saveAndFlush(labelCaptor.capture());
final Label value = labelCaptor.getValue();
// then make necessary assertions
}
}
F I R S T
I think that you only declared your mocks but never defined/created them. There's basically three ways to do so:
1) mockito extension
The convenient way in JUnit 5 is to use the MockitoExtension:
#ExtendWith(MockitoExtension.class)
public class LabelServiceImplTest {
// declare mocks, spies and captors ...
// system under test
#InjectMocks
LabelService sut;
}
Nothing else should be needed now.
Mind that by #InjectMocks you instruct Mockito to create your system under test and inject the mocks. You may as well do that manually, e. g. by injecting mocks into the SUT's constructor. I prefer that way to have more control over the configuration of my SUT.
2) MockitoAnnotations.openMocks(testclass)
This method will inject mocks into the given object:
public class LabelServiceImplTest {
// declare mocks, spies and captors ...
// system under test
#InjectMocks
LabelService sut;
#BeforeEach
void setup() {
MockitoAnnotations.openMock(this)
// ...
}
}
On JUnit 4 you'd use MockitoAnnotations.initMocks(…) instead.
3) the old school way
public class LabelServiceImplTest {
LabelRepository labelRepositoryMock = Mockito.mock(LabelRepository.class);
// ...
// system under test
LabelServiceImpl sut;
#BeforeEach
void setup() {
sut = new LabelService(labelRepositoryMock);
// ...
}
}
S E C O N D
Your questions …
1) Do you need to create the request and the label?
Yes. You call the service using the request and the mock returns the label. I would suggest you do not use the request's property to set up your label, use a String literal instead.
2) Do you need to mock the saveAndFlush() method?
Yes. This is the part where you configure your SUT's environment to behave in a predictable way.
You might consider postfixing your mocks, spies and captors by: "Mock", "Spy" and "Captor".
You might also consider calling your system under test "sut".
#Mock
private LabelRepository labelRepositoryMock;
#Captor
ArgumentCaptor<Label> labelCaptor;
// system under test
#InjectMocks
private LabelServiceImpl sut;
This makes the test code more readably, I think.
I want to write some unit tests, that use JUnit 4.12, Mockito 1.9.5 and PowerMock 1.6.1.
The class has some fields annotated with #Mock, as well as some fields annotated with #InjectMocks.
The attribute that is annotated with #InjectMocks reaches at some point a parent constructor which contains some static method invokation, that should be mocked with PowerMock.
The problem is the first test works seamlessly, while the second test does not seem to mock the static methods at all.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ StaticClass.class })
public class TestClass {
#Mock
private SomeClass attribute1;
#InjectMocks
private SomeOtherClass attribute2;
#BeforeClass
public static void setUp() {
PowerMockito.mockStatic(StaticClass.class);
when(StaticClass.staticMethod(any(), any()).thenReturn(new SomeConcreteClass());
}
#Test
public void test1() {
assertEquals(attribute2.method1(), value1);
}
#Test
public void test2() {
assertEquals(attribute2.method2(), value2);
}
}
public class SomeOtherClass {
private SomeClass attribute;
public SomeOtherClass() {
SomeConcreteClass value = StaticClass.staticMethod(argument1, argument2);
value.someOtherMethod();
}
}
As mentioned before, the first test passes and the StaticClass.staticMethod() is mocked as expected by PowerMock.
The second test does not pass and it throws a NullPointerException at line when someOtherMethod is called on value (because value = null, as the StaticClass.staticMethod was not mocked anymore by PowerMock).
As explained in (Mocking behaviour resets after each test with PowerMock) Powermock resets the mocks before each test.
For some reason it works the first time - there exists
an unresolved bug report for that issue (https://github.com/powermock/powermock/issues/398).
Its arguably bad design, but a way to do what you want is the following:
Instead of relying on the annotation set up the mocks manually.
private SomeClass attribute;
private SomeOtherClass testClass;
#Before
public void setUp() {
PowerMockito.mockStatic(StaticClass.class);
Mockito.when(StaticClass.staticMethod(anyString())).thenReturn(new SomeConcreteClass());
attribute = Mockito.mock(SomeClass.class);
testClass = new SomeOtherClass();
// assign mock manually
testClass.attribute = attribute;
}
The prefered way would be to supply the attribute using the constructor of SomeOtherClass, however since you seem to use a empty constructor
you will have to set the value from the outside. If the attribute instance is not accessible you might be forced to use reflections.
The cleaner way would be to refactor the constructor of you SomeOtherClass to not use a static method inside. Instead passing SomeConcreteClass as a parameter to the constructor is the way to go.
Some people even say you should not have any logic inside of a constructor.
I've been writing a lot of JUnit tests lately and see this same boilerplate pattern.
public class MathOpTest {
private MathOp a;
#Before
public void setUp(){
a = new MathOp();
}
...
}
Is there an annotation to set this up for me as I always need to write a setUp method and it usually only has the single class I'm testing.
Something like:
public class MathOpTest {
#TestSubject
private MathOp a;
...
}
You can assign the fields when they are declared:
public class MathOpTest {
private final MathOp mathOp = new MathOp();
...
}
This is simple and straight-forward, so I recommend that you assign fields in your test class at declaration time whenever possible (certainly in the case you gave).
If you want to understand a bit more, read on.
JUnit will create a unique instance of your test class for each test method, so even if your test modifies internal state of MathOp, using fields this way is safe as long as your tests don't modify global state.
For JUnit4-style tests (i.e. tests that do not extend junit.framework.TestCase) JUnit will create the test class just before the test method is run, and make it eligible for garbage collection after the test method completes.
Use #Before methods for more complex initialization.
Usually I use #Before when:
Initialization of the field is complex
Initialization of the field requires calling code that is declared to throw a checked exception
You need to do initialization after a #Rule has been applied (for instance, injecting a mock into a constructor)
Usually you would create the object under test in the test method when the class needs to be constructed different ways for different use cases.
Examples
Here is an example of using #Before and initMocks():
public class MathOpTest {
#Mock private Calculator mockCalculator;
#Mock private Supplier<Double> mockPreviousResultSupplier;
private MathOp mathOp;
#Before
public void createMathOp() {
MockitoAnnotations.initMocks(this);
mathOp = new MathOp(
mockCalculator, mockPreviousResultSupplier);
}
...
}
Here's an example of a #Before method that uses the result of a #Rule:
public class MyWriterTest {
#Rule public final TemporaryFolder folder = new TemporaryFolder();
private File output;
private MyWriter writer;
#Before
public void createMyWriter() {
output = folder.newFile();
writer = new MyWriter(output);
}
...
}
Aside: I personally wouldn't recommend using #InjectMocks to create the class you are testing. It's too much magic for my taste. Having an explicit constructor is cleaner and simpler, and I like my tests to be clear and simple :-)
Nothing like this directly exists in vanilla JUnit to my recollection. Most people elect to either initialize their test subject in a #Before statement, or inside of their tests. In its defense, it makes it clear what is being established before the tests are run, and it always resets the state of your test object.
If you're using Mockito, you actually do have the benefits of declaring a class and annotating it with #InjectMocks to both instantiate the class and inject whatever #Mock classes you had prior.
I have got a problem with testing how many times concrete methods (IFunction in the Operation instance) is invoked.
According to:
http://easymock.org/user-guide.html#mocking-annotations
http://www.ibm.com/developerworks/library/j-easymock/
How to use EasyMock expect
I wrote something as:
class Operation{
public double[] calculateSth(IFunction function, int [] t){
for(int i=0 ; i<5 ; i+=1)
function(t, new int[]{1,2,3});
return new double[]{1,2,3};
}
}
interface IFunction{
double f(int[] a, int[]b);
}
class ConcreteF implements IFunction{
double f(int[]a, int[]b){
return 5;
}
}
And my test class:
#TestSubject
Operation op;
#Mock
IFunction function;
#Before
public void setUp() throws Sth{
op=new Operation();
function = EasyMock.createMock(IFunction.class);
}
#Test
public void howManyTimes(){
EasyMock.expect(function.f(EasyMock.notNull(), EasyMock.notNull())
)
.andReturn((double)EasyMock.anyDouble()).times(3);
EasyMock.replay(function);
op.calculateSth(function, new double[]{0,0,0});
//verify
EasyMock.verify(function);
}
Result:
java.lang.NullPointerException
at org.easymock.internal.Injector.injectMocks(Injector.java:80)
at org.easymock.EasyMockSupport.injectMocks(EasyMockSupport.java:624)
at org.easymock.EasyMockRunner.withBefores(EasyMockRunner.java:50)
It's my first time using easymock and i don't know how to fix it ;/
I'll answer this question without going into the details of whether the original method does anything useful (the code doesn't even compile anyway), let alone the test method.
#TestSubject Operation op;
This line is a suspect. I realize that you are instantiating it in the #Before annotated setUp method, but it looks like the Easymock tries to inject the mocks (the ones annotated with #Mock) before it does anything (and understandably so) and blows up since the reference is null at that point.
The annotation support introduced in v3.2 is also seen as a way to eliminate the need for setUp method. But you seem to be mixing both and using it wrongly. Choose one or the other - I'd recommend you to use the annotations.
Quoting the Easymock user guide (this user guide is as good as it can ever be, so be sure read this up before using the library),
#RunWith(EasyMockRunner.class)
public class ExampleTest {
#TestSubject
private ClassUnderTest classUnderTest = new ClassUnderTest(); // 2
#Mock
private Collaborator mock; // 1
#Test
public void testRemoveNonExistingDocument() {
replay(mock);
classUnderTest.removeDocument("Does not exist");
}
}
The mock is instantiated by the runner at step 1. It is then set by
the runner, to the listener field on step 2. The setUp method can be
removed since all the initialization was done by the runner.