I have used Mockito very long time. With Mockito 4.7.0 version (and also for example with the version 3.12.4) the code:
A a = mock(A.class);
when(a.doX()).thenReturn("X");
causes the java.lang.NullPointerException in the second line.
When I print the content of the variable a
System.out.println(a);
I got also "java.lang.NullPointerException".
For any other class the Mockito.mock and Mockito.when are working perfectly and if I print a content of some other class instance b I got "Mock for B, hashcode: some hash code"
Do you know what could be problem? My example is simplified and I can't show the actual classes.
I don't have your code, but I tried to be the more generic as I can.
I have test like the one below and it works great.
Hope to been helpful.
#ExtendWith(MockitoExtension.class)
class MyTest {
#Mock
private AClass aclass;
#Mock
private BClass bclass;
#Mock
private CClass cclass;
#Test
void testExecute() {
when(aclass.getAbc(any(String.class), any(Date.class), anyString()))
.thenAnswer(i -> getAbc(i.getArgument(0), i.getArgument(1), i.getArgument(2)));
when(bclass.isOk())
.thenAnswer(i -> false);
when(cclass.getCdf(anyString()))
.thenAnswer(i -> getCdf());
...
...
...
}
private List<ABC> getAbc(final String myString, final Date now, final String x) {
...
...
...
}
private CDF getCdf() {
...
...
...
}
}
As you can see, for a simple answer I write the answer directly, for a more complex one, I create a private method with the same name and use it as answer.
Your code will still call the real method, unless A is an interface. I assume it is an implementation (a class) in your code.
A a = mock(A.class);
when(a.doX()).thenReturn("X");
// ^^^^^^^-- this is calling the real method
If you must use the class and cannot switch to an interface, you have do use Mockito.doReturn instead of Mockito.when:
A a = mock(A.class);
doReturn("X").when(a).doX();
But it is probably better to extract an interface and create mocks from the interface, not by subclassing your real class.
Related
Let's assume I have an object like this:
public ClassA() {
public void start() {
...
ClassB something = getSomeStuff();
...
}
protected ClassB getSomeStuff() {
return new ClassB(render, response);
}
}
Then I'm trying to do some unit-testing like this where I do a spy on a method-call on a spied object:
#Spy private ClassA classA;
#Mock private ClassC classC;
...
#Test
void test1() {
ClassB classB = spy(classA.getSomeStuff());
doReturn(classC).when(classB).getResults();
classA.start();
}
When I run this test and it comes down to this last line, I can see in my debugger that it is not returning classC.
Is this because it is not possible to do nested spying? Or is somehting wrong in my setup? Or should I approach this differently?
Details:
junit: 5.7.0
mockito: 3.12.4
When we look at the code presented, we see that calling classA.getSomeStuff() will return a new instance of ClassB with every call, i.e. classA.getSomeStuff() == classA.getSomeStuff() will evaluate to false.
What does that mean for our test setup? We construct a spy:
ClassB classB = spy(classA.getSomeStuff());
but this spy is never used. When we call classA.start(), it will call classA.getSomeStuff() again, and a new (non-spy) ClassB-instance is returned.
This is an example of code that is difficult to test: we have no easy way to control or verify the behaviour of the ClassB-instance used during the test. We normally avoid this problem by using the Inversion of Control principle (wikipedia.com). Whether this is applicable in this situation I cannot say. For this, I would have to see more of the code, and it would most probably be out of scope for StackOverflow.
As a quick and dirty fix, we can mock the call to classA.getSomeStuff() after we have created our mock:
#Spy private ClassA classA;
#Mock private ClassC classC;
...
#Test
void test1() {
ClassB classB = spy(classA.getSomeStuff());
when(classB.getResults()).thenReturn(classC);
when(classA.getSomeStuff()).thenReturn(classB);
classA.start();
}
As an aside: When using mockito, we should prefer the form
when(someMock.someMethod()).thenReturn(someResult);
over
doReturn(someResult).when(someMock).someMethod();
The former guarantees type safety at compile time, the latter does not. It is not always possible to use the former form (e.g. for methods returning void we have to use the latter form).
Given synchronized and Lombok's #Synchronized, the latter causes a NullPointerException when mocking a method under test. Given
public class Problem
{
public Problem()
{
// Expensive initialization,
// so use Mock, not Spy
}
public synchronized String a()
{
return "a";
}
#Synchronized // <-- Causes NPE during tests, literally, here
public String b()
{
return "b";
}
}
and the Jupiter test class
class ProblemTest
{
#Mock
private Problem subject;
#BeforeEach
void setup()
{
initMocks(this);
// There is more mocking. Please don't let the simplicity
// of this example throw you off.
doCallRealMethod().when( subject ).a();
doCallRealMethod().when( subject ).b();
// This is a hack, but works. Can we rely on this?
// ReflectionTestUtils.setField( subject, "$lock", new Object[0] );
}
#Test
void a()
{
// Succeeds
assertEquals( "a", subject.a() );
}
#Test
void b()
{
// NullPointerException during tests
assertEquals( "b", subject.b() );
}
}
Lombok adds something like the following:
private final Object $lock = new Object[0]; // We can't rely on this name
...
public String b()
{
synchronized($lock)
{
return "b";
}
}
How to mock a method that is decorated with Lombok's default #Synchronized annotation?
Here is the stack trace, though it is unhelpful. I suspect Lombok adds a field as in my example above, and of course that is not injected into the mock, so voilĂ , NPE.
java.lang.NullPointerException
at com.ericdraken.Problem.b(Problem.java:16) // <-- #Synchronized keyword
at com.ericdraken.ProblemTest.b(ProblemTest.java:43) // <-- assertEquals( "b", subject.b() );
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
... [snip] ...
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
This isn't an issue with Lombok, the following also fails.
#ExtendWith({MockitoExtension.class})
#MockitoSettings(strictness = Strictness.LENIENT)
public class ProblemTest {
#Mock
private Problem subject;
#BeforeEach
void setup()
{
doCallRealMethod().when( subject ).c();
}
#Test
void c()
{
// NullPointerException during tests
assertEquals( "c", subject.c() );
}
}
class Problem
{
private final Map<String,String> c = new HashMap<>(){{put("c","c");}};
public String c(){
return c.get("c");
}
}
To be precise, you are not really mocking Problem, you are partially mocking via doCallRealMethod hence the issue.
This is also called out in Mockito's documentation,
Mockito.spy() is a recommended way of creating partial mocks. The reason is it guarantees real methods are called against correctly constructed object because you're responsible for constructing the object passed to spy() method.
doCallRealMethod() is called on a mock which is not guaranteed to have the object created the way it's supposed to be.
So to answer your question, yes that's the way you create a mock, but doCallRealMethod is always a gamble irrespective of Lombok.
You can use spy if you really want to call the actual method.
#Test
void c() {
Problem spyProblem = Mockito.spy(new Problem());
assertEquals("c", spyProblem.c());
verify(spyProblem, Mockito.times(1)).c();
}
The core problem is that you are combining calling the real method with a mock rather than a spy. This is dangerous in general, as whether it works for anything depends very much on the internal implementation of the method in question.
Lombok only matters because it works by altering that internal implementation during compilation, in a way that happens to require proper object initialization to work where the original method does not.
If you're going to configure a mock to call the real method, you should probably use a spy instead.
Synopsis
Project Lombok has the #Synchronized annotation on methods to hide the underlying and auto-generated private lock(s), whereas synchronized locks on this.
When using a Mockito mock (not a spy, because there are situations when we don't want a full object instantiated), fields are not initialized. That means as well the auto-generated "lock" field is null which causes the NPE.
Solution 1 - Field injection
Looking at Lombok source code, we see that Lombok uses the following lock names:
private static final String INSTANCE_LOCK_NAME = "$lock";
private static final String STATIC_LOCK_NAME = "$LOCK";
Unless Lombok suddenly changes this in the future, this means we can do field injection even if it feels like a "hack":
#BeforeEach
void setup()
{
initMocks(this);
...
ReflectionTestUtils.setField( subject, "$lock", new Object[0] );
}
Solution 2 - Declare a lock, then field injection
The question asks about #Synchronized, not #Synchronized("someLockName"), but if you can explicitly declare the lock name, then you can use solution one with confidence about the lock field name.
I have following Java class:
public class FooServiceImpl {
private BarService barService;
public String generateFoo() {
String barValue = barService.generateBar();
return customFoo() + barValue;
}
public String customFoo() {
return "abc";
}
}
And here is exemplary Spock test method:
def "generate foo bar"() {
setup:
def barService = Mock(BarService) {
generateBar() >> "Bar"
}
FooServiceImpl spyFooService =
Spy(FooServiceImpl, constructorArgs: [[barService: barService]])
spyFooService.customFoo() >> "foo"
when:
def fooValue = spyFooService.generateFoo()
then:
fooValue == "fooBar"
}
I try to create a Spy object for FooServiceImpl class but I get following error:
org.codehaus.groovy.runtime.metaclass.MissingPropertyExceptionNoStack:
No such property: barService for class:
com.foo.FooServiceImpl$$EnhancerByCGL`
I can't add a constructor to FooServiceImpl or setter for BarService, so I want to use map constructor. Is this possible?
Note: according to this issue it should work
The easiest solution in your case would be to make this field protected instead of private. When you create a spy object from a class, CGLIB is involved and it creates as subclass from the class you are trying to create spy from - com.foo.FooServiceImpl$$EnhancerByCGL in your case. The thing is that the field you are trying to modify is a private field and according to regular subclassing strategy in Java, private field does not get inherited in child class. That is why field barService does not exist in spy object
ATTENTION: IntelliJ's debugger may tell you that barService is present in this spyFromService instance, however this is IDE's bug - if you list all available fields from spyFromService.class.fields or spyFromService.class.declaredFields you wont find barService field here.
Another problem is that when CGLIB gets involved in object creation process it also gets involved if it comes to invoking methods. This is why adding dynamic fields to a class or instance via Groovy's metaprogramming features wont work. Otherwise you would be able to do things like:
spyFromService.metaClass.barService = barService
or
spyFromService.class.metaClass.barService = barService
Alternatively you could get rid of spy object and use a real instance in your test. Then
FooServiceImpl spyFromService = new FooServiceImpl()
spyFromService.#barService = barService
will work. However you won't be able to stub existing customFoo() method and you will have to rely on what its real implementation returns.
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.
I was wondering whether there's a way to mock the field which is being autowired.
Consider the following case.
I have a class name A
public class A {
#Autowired
private B b;
public void aMethod() {
b.method();
}
}
The other class B looks like this
public class B {
public void method() {
// some code
}
}
Now i want to write junit for the method.
I know there's a way to mock the autowired field like this.
public class TestA {
#InjectMock
private A a;
#Mock
private B b;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
public void testAMethod() {
// write test case.
}
}
But my question is -> Is there a way to mock the autowired field inside method after creating object with new.
eg
public class TestA {
public void testAMethod() {
A a =new A();
// how to mock the B instance in it.
}
}
Please suggest or there's no way to do this????
I dont want to change from private modifier. Nor i want to add getter's and setters or reflection. I just want to know is there a way to mock the B instance after creating the new object of A class.
How about ReflectionTestUtils?
A a = new A();
B b = mock(B.class);
ReflectionTestUtils.setField(a, "b", b);
It's still reflection-based and has all related drawbacks, though it's quite simple and easy to read.
You can not do that with mockito, this would require to modify the bytecode of the class being tested. However Powermock allows such stubs. Note though that I and the creator of Powermock - Johan Haleby - would push for a refactoring instead of using Powermock. Powermock is very powerful, maybe too much, and working allows anyone to write legacy code, that would be difficultly maintainable or extensible (property you can find in poorly designed legacy code).
In your case I don't know what's wrong in your case with the dependency injection. However if the code need a new instance of B, it may be useful to have inject in A a factory/provider/builder class which will make a new instance of B. Such code can be easily stubbed with Mockito.