Bug in Mockito with Grails/Groovy - unit-testing

I am using Mockito 1.9 with Grails 1.3.7 and I have a strange bug.
The following test case in java works:
import static org.mockito.Mockito.*;
public class MockitoTests extends TestCase {
#Test
public void testSomeVoidMethod(){
TestClass spy = spy(new TestClass());
doNothing().when(spy).someVoidMethod();
}
public static class TestClass {
public void someVoidMethod(){
}
}
}
This test in groovy does not work:
import static org.mockito.Mockito.*
public class MockitoTests extends TestCase {
public void testSomeVoidMethod() {
def testClassMock = spy(new TestClass())
doNothing().when(testClassMock).someVoidMethod()
}
}
public class TestClass{
public void someVoidMethod(){
}
}
This is the error message:
only void methods can doNothing()!
Example of correct use of doNothing():
doNothing().
doThrow(new RuntimeException())
.when(mock).someVoidMethod();
Above means:
someVoidMethod() does nothing the 1st time but throws an exception the 2nd time is called
org.mockito.exceptions.base.MockitoException:
Only void methods can doNothing()!
Example of correct use of doNothing():
doNothing().
doThrow(new RuntimeException())
.when(mock).someVoidMethod();
Above means:
someVoidMethod() does nothing the 1st time but throws an exception the 2nd time is called
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createPogoSite(CallSiteArray.java:129)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:146)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:40)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
Does anymone observed the same error?

The problem is Groovy is intercepting your method call before it reaches someVoidMethod. The method actually being called is getMetaClass which is not a void method.
You can verify this is happening by replacing:
doNothing().when(testClassMock).someVoidMethod()
with:
doReturn(testClassMock.getMetaClass()).when(testClassMock).someVoidMethod()
I'm not sure you will be able to get around this issue using stock Mockito and Groovy.

Related

Mockito method call stub not working - Mockito.doReturn(false).when(studentServiceImpl).myClass().isValidUser(ArgumentMatchers.anyInt());

adding test cases for getStudent method, this is having internal calls
1- is repository call - stubbing this call working fine
2- validate user call - stubbing this call not working, showing some error and test case failed.
Service Class
#Service
public class StudentServiceImpl implements StudentService {
#Autowired
FakeStudentRepository fakeStudentRepository;
#Override
public Optional<Student> getStudent(int id) {
Optional<Student> student = fakeStudentRepository.getStudent(id);
boolean isValid = myClass().isValidUser(student.get().getId());
if(!isValid) {
return Optional.empty();
}
return student;
}
public MyTestClass myClass() {
return new MyTestClass();
}
}
MyTestClass
public class MyTestClass {
public boolean isValidUser(int id) {
return true;
}
}
Test Class
#SpringBootTest
class StudentServiceImplTest {
#Mock
FakeStudentRepository fakeStudentRepository;
#InjectMocks
StudentServiceImpl studentServiceImpl;
#BeforeEach
public void setup() {
studentServiceImpl = Mockito.spy(StudentServiceImpl.class);
MockitoAnnotations.initMocks(this);
}
#Test
void getStudent() {
Optional<Student> student = Optional.of(Student.builder().id(1).firstName("Rahul").lastName("rahul")
.mobile("XXXXXX").build());
Mockito.doReturn(student)
.when(fakeStudentRepository).getStudent(ArgumentMatchers.anyInt());
Mockito.doReturn(false)
.when(studentServiceImpl).myClass().isValidUser(ArgumentMatchers.anyInt());
Optional<Student> resultStudent = studentServiceImpl.getStudent(student.get().getId());
assertEquals(resultStudent.get().getId(), student.get().getId());
}
}
Error
org.mockito.exceptions.misusing.WrongTypeOfReturnValue: Boolean
cannot be returned by myClass() myClass() should return MyTestClass
If you're unsure why you're getting above error read on. Due to the
nature of the syntax above problem might occur because:
1. This exception might occur in wrongly written multi-threaded tests. Please refer to Mockito FAQ on limitations of concurrency
testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
The error Message says it: You are mocking studentServiceImpl.myClass() and try to return true. It’s not possible to mock the end of a call chain as you try with your second Mockito expression.
To do what you want requires to mock myClass() first by returning a mocked class instance and mock isValidUser on that.

Mocking HystrixObservableCommand results in real .toObservable() getting called

I have a HystrixObservableCommand that I'd like to mock using Mockito:
public class LoginWithEmailCommand extends HystrixObservableCommand<Boolean> {
// stuff...
}
With a test that looks like this:
#RunWith(MockitoJUnitRunner.class)
public class ExampleTest {
#Mock
Observable<Result> mockObs;
#Test
public void mockwtf() {
LoginWithEmailCommand cmd = mock(LoginWithEmailCommand.class);
when(cmd.toObservable()).thenReturn(mockObs);
cmd.toObservable();
}
}
However, running this test results in a NullPointerException:
java.lang.NullPointerException
at com.netflix.hystrix.AbstractCommand.toObservable(AbstractCommand.java:342)
at com.netflix.hystrix.HystrixObservableCommand.toObservable(HystrixObservableCommand.java:35)
Why does the real .toObservable() keep getting called? Setting a breakpoint shows that the LoginWithEmailCommand object being created is a generated, proxied object...
ANOTHER CLUE: If I add this override into the ObservableCommand, mocking works:
#Override
public Observable<Boolean> toObservable() {
return super.toObservable();
}
...is there a cleaner way to make this work than having to put unused toObservable overrides in?
This is my solution for this, so far -- perhaps there is a cleaner way...
Step 1: Create a new BaseCommand in my package:
public abstract class BaseCommand<T> extends HystrixObservableCommand<T> {
// protected ctors go here
#Override
public Observable<T> toObservable() {
return super.toObservable();
}
}
Step 2: Extend my commands from this base instead.
public class LoginWithEmailCommand extends BaseCommand<Boolean> {
// stuff...
}
and now the mocks work correctly.

Why do I have to extend PowerMockTestCase?

The below test throws java.lang.IllegalStateException: no last call on a mock available when I don't extend from the PowerMockTestCase.
The error disappears as soon as I extend from PowerMockTestCase. Why exactly is this happening?
import static org.junit.Assert.assertEquals;
import org.easymock.EasyMock;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
#PrepareForTest({ IdGenerator.class, ServiceRegistartor.class })
public class SnippetTest extends PowerMockTestCase{
#org.testng.annotations.Test
public void testRegisterService() throws Exception {
long expectedId = 42;
// We create a new instance of test class under test as usually.
ServiceRegistartor tested = new ServiceRegistartor();
// This is the way to tell PowerMock to mock all static methods of a
// given class
PowerMock.mockStatic(IdGenerator.class);
/*
* The static method call to IdGenerator.generateNewId() expectation.
* This is why we need PowerMock.
*/
EasyMock.expect(IdGenerator.generateNewId()).andReturn(expectedId).once();
// Note how we replay the class, not the instance!
PowerMock.replay(IdGenerator.class);
long actualId = tested.registerService(new Object());
// Note how we verify the class, not the instance!
PowerMock.verify(IdGenerator.class);
// Assert that the ID is correct
assertEquals(expectedId, actualId);
}
}
While using PowerMock for static mocking, there is a class level instrumentation happening to make your mocking work. PowerMockTestCase class has a code (method beforePowerMockTestClass()) to switch your regular class loader to powermock class loader which orchestrates mocking injection. Hence you need to extend this class for static mock to work.
You need to have the PowerMock class-loaders configured so that the static classes can be intercepted (defined using the #PrepareForTest annotation).
You don't have to extend from PowerMockTestCase. For most cases you can also configure TestNG with a PowerMockObjectFactory instead:
#PrepareForTest({ IdGenerator.class, ServiceRegistartor.class })
public class SnippetTest {
#ObjectFactory
public IObjectFactory objectFactory() {
return new PowerMockObjectFactory();
}
#org.testng.annotations.Test
public void testRegisterService() throws Exception {
...
}
}

How do I mock a static method in final class

I have some code that has a static method inside a final class. I was trying to mock that method. I have tried doing a few things..
public final Class Class1{
public static void doSomething(){
}
}
How can I mock doSomething()? I have tried..
Class1 c1=PowerMockito.mock(Class1.class)
PowerMockito.mockSatic(Class1.class);
Mockito.doNothing().when(c1).doSomething();
This gives me an error:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at com.cerner.devcenter.wag.textHandler.AssessmentFactory_Test.testGetGradeReport_HTMLAssessment(AssessmentFactory_Test.java:63)
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
at org.powermock.api.mockito.internal.invocation.MockitoMethodInvocationControl.performIntercept(MockitoMethodInvocationControl.java:260)
Most used testing framework is JUnit 4. So if you are using it you need to annotate test class with:
#RunWith( PowerMockRunner.class )
#PrepareForTest( Class1.class )
Than
PowerMockito.mockSatic(Class1.class);
Mockito.doNothing().when(c1).doSomething();
Mockito.when(Class1.doSomething()).thenReturn(fakedValue);
// call of static method is required to mock it
PowerMockito.doNothing().when(Class1.class);
Class1.doSomething();
I use PowerMock. It let's you do things Mockito can't do.
https://github.com/powermock/powermock/wiki
#RunWith(PowerMockRunner.class)
#PrepareForTest(StaticClass.class)
public class StaticTest {
#Before
public void setUp() {
PowerMockito.mockStatic(Bukkit.class);
//When a static method with no arguments is called.
when(StaticClass.callMethod1()).thenReturn(value);
//When a static method with an argument is called.
when(StaticClass.callMethod2(argument)).thenReturn(value2);
//Use when you don't care what the argument is..
//use Mockito.anyInt(), Mockito.anyDouble(), etc.
when(StaticClass.callMethod3(Mockito.anyString())).thenReturn(value3);
}
#Test
public void VerifyStaticMethodsWork() {
assertEquals(value, StaticClass.callMethod1());
assertEquals(value2, StaticClass.callMethod2(argument));
assertEquals(value3, StaticClass.callMethod3("Hello"));
}
}

Replacing PowerMock's #PrepareForTest programmatically?

I am using PowerMock to mock static methods in junit tests, typically done as follows:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Foo.class,Bar.class})
public class SomeUnitTest {
#Before
public void setUpTest() {
setUpFoo();
setUpBar();
}
private void setUpFoo() {
mockStatic(Foo.class);
when(Foo.someStaticMethod()).thenReturn(1);
}
private void setUpBar() {
mockStatic(Bar.class);
when(Bar.someStaticMethod()).thenReturn(2);
}
#Test
public void someTestCase() {
...
}
}
This works fine, but I'm finding that specifying the #PrepareForTest annotation is preventing me from making my testing API flexible.
What I'd like to do is something like the following:
public class MockLibraryOne {
public static void setUpLibraryOne() {
setUpFoo();
setUpBar();
}
private static void setUpFoo() {
mockStatic(Foo.class);
when(Foo.someStaticMethod()).thenReturn(1);
}
private static void setUpBar() {
mockStatic(Bar.class);
when(Bar.someStaticMethod()).thenReturn(2);
}
}
#RunWith(PowerMockRunner.class)
public class SomeUnitTest {
#Before
public void setUpTest() {
MockLibraryOne.setUpLibraryOne();
}
#Test
public void someTestCase() {
...
}
}
Here my unit test has a dependency on LibraryOne, but it does not know which classes LibraryOne depends on, so it does not know which classes to add to the #PrepareForTest annotation.
I could make SomeUnitTest extend MockLibraryOne and add the #PrepareForTest annotation to the MockLibraryOne class, but I will have dependencies on more than just MockLibraryOne in other unit tests, so inheritance is not a general solution.
Is there some way of programmatically preparing a class for testing under PowerMock, instead of using the #PrepareForTest annotation? For example, something like the following:
public class MockLibraryOne {
public static void setUpLibraryOne() {
setUpFoo();
setUpBar();
}
private static void setUpFoo() {
prepareForTest(Foo.class);
mockStatic(Foo.class);
when(Foo.someStaticMethod()).thenReturn(1);
}
private static void setUpBar() {
prepareForTest(Bar.class);
mockStatic(Bar.class);
when(Bar.someStaticMethod()).thenReturn(2);
}
}
I guess it would be nice if PowerMockRunner processed the #PrepareForTest annotation a little differently: for each specified class, it should not only add that class (and its hierarchy) to the list of classes to prepare for mocking, but then examine that class to see if it has any #PrepareForTest annotations as well:
#RunWith(PowerMockRunner.class)
#PrepareForTest({MockLibraryOne.class})
public class SomeUnitTest {
...
}
#PrepareForTest({Foo.class,Bar.class})
public class MockLibraryOne {
...
}
}
So in this the #PrepareForTest annotation on SomeUnitTest would find MockLibraryOne, and the #PrepareForTest annotation there would drag in Foo.class and Bar.class as well.
So perhaps writing my own test runner to replace PowerMockRunner may be a solution.
Or perhaps there's a simpler solution, using PowerMockAgent class, for example?
edit: Mock Policies may be one solution: https://code.google.com/p/powermock/wiki/MockPolicies
edit: Mock Policies works with PowerMockRunner but not (it seems) with PowerMockRule (which I sometimes require due to class loader issues).
What you try to achieve will not work.
The problem is that powermock must rewrite the client class's code to intercept the static invocation and it can't do this after the class is loaded. Thus it can only prepare a class for test before it is loaded.
Let's assume you want to mock the System.currentTimeMillis invocation in the following simple class.
class SystemClock {
public long getTime() {
return System.currentTimeMillis();
}
}
Powermock will not change the code of java.lang.System.currentTimeMillis, because it can't. Instead it changes the SystemClock's byte code so that it does not invoke System.currentTimeMillis anymore. Instead it invokes some other object that belong to powermock.
This is how powermock get's full control over the return value and allows you to write a test like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ SystemClock.class })
public class PowerMockitoTest {
#Test
public void systemTimeMillis() {
SystemClock systemClock = new SystemClock();
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.currentTimeMillis()).thenReturn(12345L);
long time = systemClock.getTime();
assertEquals(12345L, time);
}
}
You can see that powermock has rewritten the client class in the stacktrace of your debugger. Set a breakpoint at SystemClock.getTime and step into the invoked method.
As you can see SystemClock invokes a MockGateway.
If you take a look at the variables on the stack of the MockGateway invocation, you can see how the original System.currentTimeMillis method is handled.
Perhaps you're looking for a mock policy?
Could you help this (taken from documentation)?
You can also prepare whole packages for test by using wildcards:
#PrepareForTest(fullyQualifiedNames="com.mypackage.*")
So you can add the whole library to your prepare...
Why do you even want to mock static methods? Why not wrap those static methods in a class that you can mock with mockito?
class FooWraper {
void someMethod() {
Foo.someStaticMethod()
}
}
and then you can create a mock of your FooWraper. No need to use Powermock at all...