Mockito: verifying method call from internal anonymous class - java

I have a class under test which contains a method which has an inner anonymous class. One of the methods in the anonymous class calls a method from the class under test, but Mockito doesn't seem to realize this.
public class ClassUnderTest {
Dependency dependency;
public ClassUnderTest(Dependency d) {
dependency = d;
}
public void method() {
dependency.returnsObservable().observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io()).subscribe(new Observer<SupportClass> {
/* Other methods omitted */
public void onComplete() {
outerMethod();
})
}
public void outerMethod() {
blah;
}
}
My test code:
public class TestClass {
ClassUnderTest underTest;
Dependency dependency;
#Before
public void setUp() throws Exception {
dependency = Mockito.mock(Dependency.class);
underTest = Mockito.spy(new ClassUnderTest(dependency));
}
#Test
public void method() throws
Mockito.when(dependency.returnObservable()).thenReturn(Observable.just(new SupportClass());
Mockito.doNothing().when(underTest).outerMethod();
underTest.method();
Mockito.verify(underTest).outerMethod();
}
}
For some reason that I can't seem to figure out, Mockito can't detect that outerMethod() is being called, even though I have manually verified by stepping through line by line in the debugger. I have also verified that the call to the dependency object returns the proper observable with the correct content, and the onComplete() and outerMethod() methods do get called. I'm just confused why Mockito doesn't detect it as such.
This is the error that it spits out:
Wanted but not invoked:
classUnderTest.outerMethod();
-> at (file and line number)
However, there was exactly 1 interaction with this mock:
classUnderTest.method();
-> at (file and line number)
Is there anything obvious I'm missing?

You're changing between schedulers so it can cause some issues when testing (your code may reach the verify method before the actual method is invoked
Check this article explaining how to test asynchronous code with RxJava and Mockito
TL;DR
Add a TestRule that set all schedulers to trampoline so it behaves synchronously:
public class TrampolineSchedulerRule implements TestRule {
#Override
public Statement apply(final Statement base, Description d) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
RxJavaPlugins.setIoSchedulerHandler(
scheduler -> Schedulers.trampoline());
RxJavaPlugins.setComputationSchedulerHandler(
scheduler -> Schedulers.trampoline());
RxJavaPlugins.setNewThreadSchedulerHandler(
scheduler -> Schedulers.trampoline());
RxAndroidPlugins.setInitMainThreadSchedulerHandler(
scheduler -> Schedulers.trampoline());
try {
base.evaluate();
} finally {
RxJavaPlugins.reset();
RxAndroidPlugins.reset();
}
}
};
}
}

Related

Mockito mocking same named method with similar signatures

I have a class, say SimpleClass, that has two functions with the same name and the same number of parameters but different parameter types. Now I assume mocking their return values should be as using two when statements with the appropriate matchers but instead when I attempt that I get the following error:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced argument matcher detected here:
-> at mocks.MockTest.whenMethodsHaveSimilarSignatures(MockTest.java:28)
-> at mocks.MockTest.whenMethodsHaveSimilarSignatures(MockTest.java:28)
Here's a sample of what I'm attempting:
public class SimpleClass {
public boolean doWork(String value, String name) {
return false;
}
public boolean doWork(Integer value, String name) {
return true;
}
}
#RunWith(MockitoJUnitRunner.class)
public class MockTest {
private SimpleClass thing;
#Before
public void setup() {
thing = new SimpleClass();
}
#Test
public void whenMethodsHaveSimilarSignatures() {
when(thing.doWork(anyString(), anyString())).thenReturn(true);
when(thing.doWork(any(Integer.class), anyString())).thenReturn(false);
assertThat(thing.doWork("one", "name")).isTrue();
assertThat(thing.doWork(1, "name")).isFalse();
}
}
While I'm not a wizard at Mockito I've been using it for a while and never encountered this issue. Thoughts? I'm using Mockito-Core v2.2.9
You should not use any(Object.class) while stubbing overloaded methods because both String and Integer are child classes of Object, so specify the particular arguments during stubbing.You can also use ArgumentMatchers
when(thing.doWork(ArgumentMatchers.anyString(), ArgumentMatchers.anyString())).thenReturn(true);
when(thing.doWork(ArgumentMatchers.any(Integer.class), anyString())).thenReturn(false);
And also you are not mocking the SimpleClass
#RunWith(MockitoJUnitRunner.class)
public class MockTest {
private SimpleClass thing = Mockito.mock(SimpleClass.Class);
#Before
public void setup() {
MockitoAnnotations.initMocks(this); // need to enable these annotations programmatically
}
#Test
public void whenMethodsHaveSimilarSignatures() {
when(thing.doWork(anyString(), anyString())).thenReturn(true);
when(thing.doWork(any(Integer.class), anyString())).thenReturn(false);
//or
when(thing.doWork(ArgumentMatchers.anyString(), ArgumentMatchers.anyString())).thenReturn(true);
when(thing.doWork(ArgumentMatchers.any(Integer.class), anyString())).thenReturn(false);
assertThat(thing.doWork("one", "name")).isTrue();
assertThat(thing.doWork(1, "name")).isFalse();
}
}

Verify private static method on final class gets called using PowerMockito

I have the following class
public final class Foo {
private Foo() {}
public static void bar() {
if(baz("a", "b", new Object())) { }
}
private static boolean baz(Object... args) {
return true; // slightly abbreviated logic
}
}
And this is my Test:
#PrepareOnlyThisForTest(Foo.class)
#RunWith(PowerMockRunner.class)
public class FooTest {
#Test
public void bar() {
PowerMockito.mockStatic(Foo.class); // prepare
Foo.bar(); // execute
verifyPrivate(Foo.class, times(1)).invoke("baz", anyVararg()); // verify - fails
}
}
For that, I get the following error message - and I don't understand why...
Wanted but not invoked com.example.Foo.baz(
null );
However, there were other interactions with this mock.
Removing the prepare line above seems to make the verify line pass no matter for how many times you check for... :(
(Our SONAR code checks enforce that each test has some sort of assertXyz() in it (hence the call to verify()) and enforces a very high test coverage.)
Any ideas how to do this?
The problem with your code is that you mock Foo so your method implementations won't be called by default such that when you call Foo.call() it does nothing by default which means that it never avtually calls baz that is why you get this behavior. If you want to partially mock Foo, mock it using the option Mockito.CALLS_REAL_METHODS in order to make it call the real methods as you seem to expect, so the code should be:
#PrepareOnlyThisForTest(Foo.class)
#RunWith(PowerMockRunner.class)
public class FooTest {
#Test
public void bar() throws Exception {
PowerMockito.mockStatic(Foo.class, Mockito.CALLS_REAL_METHODS); // prepare
...
}
}

How to avoid conflict between Mockito and PowerMockito?

I need to test a few very simple classes. The first one is Child class:
public class Child extends Parent {
public int newMethod() {
anotherMethod();
protectedMethod();
return protectedMethodWithIntAsResult();
}
public void anotherMethod() {
// method body no so important
}
}
Than I have a Parent class:
public class Parent {
protected void protectedMethod() {
throw new RuntimeException("This method shouldn't be executed in child class!");
}
protected int protectedMethodWithIntAsResult() {
throw new RuntimeException("This method shouldn't be executed in child class!");
}
}
And finally my test class with single test method:
#PrepareForTest({Child.class, Parent.class})
public class ChildTest extends PowerMockTestCase {
#Test
public void test() throws Exception {
/** Given **/
Child childSpy = PowerMockito.spy(new Child());
PowerMockito.doNothing().when(childSpy, "protectedMethod");
PowerMockito.doReturn(100500).when(childSpy, "protectedMethodWithIntAsResult");
/** When **/
int retrieved = childSpy.newMethod();
/** Than **/
Assert.assertTrue(retrieved == 100500);
Mockito.verify(childSpy, times(1)).protectedMethod();
Mockito.verify(childSpy, times(1)).protectedMethodWithIntAsResult();
Mockito.verify(childSpy, times(1)).anotherMethod(); // but method was invoked 3 times.
}
}
I have a problem with last verification. Program throws an exception:
org.mockito.exceptions.verification.TooManyActualInvocations:
child.anotherMethod();
Wanted 1 time:
-> at my.project.ChildTest.test(ChildTest.java:30)
But was 3 times. Undesired invocation:
And I don't understand why. Any ideas why it happens?
The problem is happening when you call int retrieved = childSpy.newMethod() because in there you are calling anotherMethod() and protectedMethod().
Mockito assumes that you will be calling each method only ones but newMethod internally calls protectedMethod and anotherMethod and anotherMethod has already been called once.
If you remove the call to either newMethod or anotherMethod the test will run fine.

PowerMock + EasyMock: private void method without invokation

Good time!
I need to substitute the class' private void method with a mock implementation, and can't to figure out how to do this. I've tried to use such a construction:
Test test = PowerMock.createPartialMock(Test.class, "setId");
PowerMock.expectPrivate(test , "setId", EasyMock.anyLong()).andAnswer(
new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
return null;
}
});
PowerMock.replay(test);
but the internal PowerMock's class called WhiteBox invokes my "setId" method which is wrong for my task. Could someone, please, suggest, how to avoid the method invokation and possibly to replace the method body with a custom one?
Finally. I've got the solution.
The problem was I missed the following annotations:
#RunWith(PowerMockRunner.class)
#PrepareForTest(Test.class)
Anyway, it seems rather confusing that to make the PowerMock working I need to add some annotations. If that wasn't a legacy code I'd prefer Mockito.
Not quite sure that I get the question.
But for me code below works perfect and just string "Invoked!" is getting printed
and if I remove test.setS(33L); test will fail with exception:
#RunWith(PowerMockRunner.class)
#PrepareForTest(MainTest.Test2.class)
public class MainTest {
#Test
public void testName() throws Exception {
Test2 test = PowerMock.createPartialMock(Test2.class, "setS");
PowerMock.expectPrivate(test , "setS", EasyMock.anyLong()).andAnswer(
new IAnswer<Void>() {
#Override
public Void answer() throws Throwable {
System.out.println("Invoked!");
return null;
}
}).atLeastOnce();
PowerMock.replay(test);
test.setS(33L);
PowerMock.verify(test);
}
class Test2 {
long s;
private long getS() {
return s;
}
private void setS(long s) {
this.s = s;
System.out.println("Not this!");
}
}
}

JUnit test methods selection at runtime

I have one TestCase class, whcih has 5 test methods. I can directly execute this class, then all the test methods will be executed. This is fine.
Suppose If I want to execute few test methods(but not all) and those methods will be decided based on certain condition at run time, what is the solution..?
To be more clear,
I have a TestCase class "MyTestCase"
public class MyTestCase extends TestCase
{
#Test
public void test1()
{
....
}
#Test
public void test2()
{
....
}
#Test
public void test3()
{
....
}
#Test
public void test4()
{
....
}
#Test
public void test5()
{
....
}
}
If I run this class, all the tests will be executed.
But my requirement is: I don't want all methods to be executed always. Sometimes 2 methods or 3 methods or 4 methods etc....
I have an XML file, which decides what test methods have to be executed.
Whatever is there in the XML file, only those test methods should be executed.
(I have a class, which reads the XML file to get the test method names.)
Is there any way to control no of test methods to be executed in a TestCase class at run time....?
I think I have to use TestSuite class. But I am not sure on how to use it exactly.
Can any one help in solving this problem...?
Thanks in advance,
Sunil
You can use a custom TestRunner to execute this.
public class SelectiveJunitRunner extends BlockJUnit4ClassRunner {
public SelectiveJunitRunner(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
protected List<FrameworkMethod> computeTestMethods() {
//Inject ignore List
List<String> ignoreList = Arrays.asList("test2","test4");
List<FrameworkMethod> computeTestMethods = super.computeTestMethods();
List<FrameworkMethod> filteredList = new ArrayList<>();
for (FrameworkMethod frameworkMethod : computeTestMethods) {
if (!ignoreList.contains(frameworkMethod.getName()))
filteredList.add(frameworkMethod);
}
return filteredList;
}
}
Junit Test case
#RunWith(SelectiveJunitRunner.class)
public class SelectiveTest {
#Test
public void test1() {
System.out.println("1");
}
#Test
public void test2() {
System.out.println("2");
}
#Test
public void test3() {
System.out.println("3");
}
#Test
public void test4() {
System.out.println("4");
}
}

Categories

Resources