Mockito counting stubbing as invocation - java

Trying to stub a class with 2 possible invocation/return paths using custom Matcher ... ran into an interest problem.
Here is a test I wrote to illustrate ...
This might be difficult to implement, but I would have expected the 1st ArgumentMatcher is not invoked when stubbing the second when(...).thenReturn(...)
But running the code below prints foobar on stdout. Is there anything we can do to prevent this behavior? Or am I using the wrong pattern by trying to stub a single mock with multiple custom ArgumentMatcher
FYI - powermock is on my classpath for other tests (not sure if that matters but I do see it in the stack trace)
import org.junit.Test;
import org.mockito.ArgumentMatcher;
import java.io.File;
import java.io.FilenameFilter;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class MyTest {
#Test
public void name() throws Exception {
File file = mock(File.class);
when(file.list(argThat(new ArgumentMatcher<FilenameFilter>() {
#Override
public boolean matches(Object argument) {
System.out.println("foobar");
return 1 + 1 >2;
}
}))).thenReturn(null);
// at this point, mockito will attempt to run the previous matcher, treating this stub code as invocation ... and printing out 'foobar'
when(file.list(argThat(new ArgumentMatcher<FilenameFilter>() {
#Override
public boolean matches(Object argument) {
System.out.println("barbar");
return true;
}
}))).thenReturn(null);
}
}
EDIT added comments to help illustrate

If you use the doReturn() syntax, then the method is not called.
doReturn(null).when(file).list(argThat(new ArgumentMatcher<FilenameFilter>() {
#Override
public boolean matches(Object argument) {
System.out.println("barbar");
return true;
}
}));
See this answer for more details. Also, the docs explain this use-case (emphasis mine):
You can use doReturn(), [...] in place of the corresponding call with when(), for any method. It is necessary when you:
stub void methods
stub methods on spy objects (see below)
stub the same method more than once, to change the behaviour of a mock in the middle of a test.

Related

PowerMockito VerifyStatic not working in 2.0.0-beta5

I am getting an issue using powermockito (2.0.0-beta5) to verify a static method was called a certain number of times when I call a different (also static) method. The classes are prepared for test at the top of my test file The relevant code snippet is:
mockStatic(Tester.class);
when(Tester.staticMethod(anyString(), anyString())).thenAnswer(new FirstResponseWithText());
OtherClass.methodThatCallsTesterStaticMethod("", "", "", false, "");
verifyStatic(Tester.class, times(3));
Tester.sendFaqRequest(anyString(), anyString());
FirstResponseWithText is a class that extends Answer that controls the order of responses. I've used that elsewhere and it works fine.
I get the following error on the verifyStatic line:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type Class and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
verify(mock).someMethod();
verify(mock, times(10)).someMethod();
verify(mock, atLeastOnce()).someMethod();
What is the proper way to pass the class to verifyStatic? All the examples I can find online are for pre-2.x.x releases where verifyStatic did not take a class parameter.
I think the PowerMockito version is not the problem. I tested the following code with versions
1.7.3,
2.0.0-beta.5 (your version),
2.0.2.
Application classes:
package de.scrum_master.stackoverflow.q52952222;
public class Tester {
public static String sendFaqRequest(String one, String two) {
return "real response";
}
}
package de.scrum_master.stackoverflow.q52952222;
public class OtherClass {
public static void methodThatCallsTesterStaticMethod(String one, String two, String three, boolean four, String five) {
System.out.println(Tester.sendFaqRequest("A", "B"));
System.out.println(Tester.sendFaqRequest("C", "D"));
System.out.println(Tester.sendFaqRequest("E", "F"));
}
}
Test classes:
package de.scrum_master.stackoverflow.q52952222;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.util.Arrays;
public class FirstResponseWithText implements Answer {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
String methodName = invocation.getMethod().getName();
return methodName + " called with arguments: " + Arrays.toString(args);
}
}
package de.scrum_master.stackoverflow.q52952222;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.times;
import static org.powermock.api.mockito.PowerMockito.*;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ Tester.class })
public class MyTest {
#Test
public void myTest() {
// Tell PowerMockito that we want to mock static methods in this class
mockStatic(Tester.class);
// Stub return value for static method call
when(Tester.sendFaqRequest(anyString(), anyString())).thenAnswer(new FirstResponseWithText());
// Call method which calls our static method 3x
OtherClass.methodThatCallsTesterStaticMethod("", "", "", false, "");
// Verify that Tester.sendFaqRequest was called 3x
verifyStatic(Tester.class, times(3));
Tester.sendFaqRequest(anyString(), anyString());
}
}
So if this does not work for you and your Maven or Gradle dependencies are also okay, the difference is maybe in your FirstResponseWithText class. Maybe you want to show it so we can all see what kind of magic you do in there. As you can see from my sample code, I had to make several educated guesses because you only share a little snippet of test code and not MCVE like you should. This way I can only speculate and actually I do not like to because it might be a waste of time for both you and myself.

Is it possible to call a method twice, first call the real implementation, then mock the results?

I am trying to test that a recursive method properly re-curses.
The first call should therefore callRealMethod. But the second call is just to verify that it was called, and should not actually make the call but rather it should return a stubbed result.
Is there any way to do this in Mockito?
You can simply use thenCallRealMethod, followed by a regular thenReturn stub:
import org.junit.Test;
import static org.mockito.Mockito.*;
public class PartialMock {
String doIt() {
return "original";
}
#Test
public void testDoIt() {
PartialMock t = mock(PartialMock.class);
when(t.doIt())
.thenCallRealMethod()
.thenReturn("mocked");
assertEquals("original", t.doIt());
assertEquals("mocked", t.doIt());
assertEquals("mocked", t.doIt());
verify(t, times(3)).doIt();
}
}

How to capture incoming parameters with EasyMock.capture?

I'm testing a class and wanted to monitor calls to a specific method, namely to save the calling parameters for later analysis.
Testing is done with EasyMock, so it was logical to use EasyMock.capture feature. However, the examples that I managed to find do not work for me - I get the following compile error at the line with capture:
expect(T) in EasyMock cannot be applied to (void)
reason: no instance of type variable T exist so that void conforms to T
It would be great if somebody could point out my mistake(s) for me. Below is a code snippet:
import static org.easymock.EasyMock.capture;
import org.easymock.Capture;
import org.easymock.CaptureType;
import org.easymock.EasyMock;
import org.junit.Before;
class B {
}
class A {
public void doSomething(B input) {
}
}
public class ATest {
private Capture<B> capturedData;
private A testObject;
#Before
private void setUp() {
capturedData = EasyMock.newCapture(CaptureType.ALL);
testObject = EasyMock.createNiceMock(A.class);
EasyMock
.expect(testObject.doSomething(capture(capturedData)))
.anyTimes();
}
}
Thanks a lot in advance!
Your problem is not related to the capture, but to the return type of your doSomething() method:
Since A.doSomething(B input) is of return type void, you don't expect the method to return anything, thus you cannot use EasyMock.expect() for it. Instead, simply invoke the method and use EasyMock.expectLastCall(), like so:
testObject.doSomething(capture(capturedData));
EasyMock.expectLastCall().anyTimes();
EasyMock.expectLastCall() declares that you expect the last method invocation before expectLastCall() to be executed. You can then handle it just like expect(), e.g. add anyTimes() to it.

Power Mockito Throws "Unfinished stubbing" error when method is private, but not error when method is protected

I am trying to test the method 'reallyCoolMethod' gets called with the correct parameters. The problem is stubbing the 'getSillyString' method is causing errors. When the method 'getSillyString' is private, the test will fail on the second doReturn:
doReturn("superSilly").when(spy, "getSillyString", 5, false);
however when the method is protected, the test will pass. The error is:
org.mockito.exceptions.misusing.UnfinishedStubbingException:
Unfinished stubbing detected here:
-> at org.powermock.api.mockito.internal.PowerMockitoCore.doAnswer(PowerMockitoCore.java:36)
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!
Here is the class under test:
import java.util.Random;
#Singleton
public class FooBar {
#Inject
public FooBar(Foo foo, Bar bar) {
this.foo = foo;
this.bar = bar;
}
#POST
#Path("foos/")
public fooAction createFoo() {
word1 = getSillyString(4, true);
word2 = getSillyString(5, false);
int id = reallyCoolMethod(word1,word2);
}
private String getSillyString(int size, boolean allCaps){
}
}
Here is the test:
import static org.mockito.Mockito.verify;
import org.junit.Test;
import org.mockito.Mockito;
import static org.powermock.api.mockito.PowerMockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.spy;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
public class FooTest {
#Test
public void testCreateFoo() throws Exception {
Foo foo = Mockito.mock(Foo.class);
Bar bar = Mockito.mock(Bar.class);
FooBar resource = new FooBar(foo, bar);
FooBar spy = spy(resource);
doReturn("reallySilly").when(spy, "getSillyString", 4, true);
doReturn("superSilly").when(spy, "getSillyString", 5, false);
doReturn(1).when(spy).reallyCoolMethod(Mockito.anyString(),Mockito.anyString());
spy.createFoo();
verify(spy).reallyCoolMethod(Mockito.eq("reallySilly"),Mockito.Eq(superSilly));
}
}
The real answer here: you created hard-to-test code by putting an essential element of that class into a private method.
In other words: if that thing is so essential to your production code, then the better answer is to put the underlying functionality in its own class. So, you create some interface:
public interface SillyService {
public String getSillyString();
}
And then you use dependency injection to provide "some kind" of implementation to the class that needs this service.
The desire to mock a private method always is a consequence of a bad design decision. Thus the answer does not lie within Mockito or PowerMock, but by stepping back and improving that design.
For starters, one can watch these videos to learn how to write testable code instead.
And beyond that: please note that PowerMock impacts the things you can do with Mockito - as PowerMock comes with pretty much backlevel versions of Mockito. My personal recommendation: get rid of your need for PowerMock; and instead just use latest/greatest versions of Mockito.

How to mock object with constructor that takes a Class?

This is the test:
import static junit.framework.Assert.assertTrue;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.whenNew;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest( {ClassUnderTesting.class} )
public class ClassUnderTestingTest {
#Test
public void shouldInitializeMocks() throws Exception {
CollaboratorToBeMocked mockedCollaborator = mock(CollaboratorToBeMocked.class);
suppress(constructor(CollaboratorToBeMocked.class, InjectedIntoCollaborator.class));
whenNew(CollaboratorToBeMocked.class)
.withArguments(InjectedAsTypeIntoCollaborator.class)
.thenReturn(mockedCollaborator);
new ClassUnderTesting().methodUnderTesting();
assertTrue(true);
}
}
These are the classes :
public class ClassUnderTesting {
public void methodUnderTesting() {
new CollaboratorToBeMocked(InjectedAsTypeIntoCollaborator.class);
}
}
public class CollaboratorToBeMocked {
public CollaboratorToBeMocked(Class<InjectedAsTypeIntoCollaborator> clazz) {
}
public CollaboratorToBeMocked(InjectedIntoCollaborator someCollaborator) {
}
public CollaboratorToBeMocked() {
}
}
public class InjectedAsTypeIntoCollaborator {
}
public class InjectedIntoCollaborator {
}
This is the error :
org.powermock.reflect.exceptions.TooManyConstructorsFoundException: Several matching constructors found, please specify the argument parameter types so that PowerMock can determine which method you're refering to.
Matching constructors in class CollaboratorToBeMocked were:
CollaboratorToBeMocked( InjectedIntoCollaborator.class )
CollaboratorToBeMocked( java.lang.Class.class )
Here comes the question: how can I make PowerMock figure out what constructor to look for?
The problematic line is the suppress. That is where the error comes from.
Perhaps it is too late for your question. I met it today and found the solution at the following url. Basically, you need to specify your argument type like.
whenNew(MimeMessage.class).**withParameterTypes(MyParameterType.class)**.withArguments(isA(MyParameter.class)).thenReturn(mimeMessageMock);
http://groups.google.com/group/powermock/msg/347f6ef1fb34d946?pli=1
Hope it can help you. :)
I didn't know of PowerMock until you wrote your question, but did some reading and found this in their documentation. Still I am not really sure if that helps you:
If the super class have several
constructors it's possible to tell
PowerMock to only suppress a specific
one. Let's say you have a class called
ClassWithSeveralConstructors that has
one constructor that takes a String
and another constructor that takes an
int as an argument and you only want
to suppress the String constructor.
You can do this using the
suppress(constructor(ClassWithSeveralConstructors.class, String.class));
method.
found at http://code.google.com/p/powermock/wiki/SuppressUnwantedBehavior
Isn't it the thing you wanted?
EDIT: Now I see, you've already tried suppressing. But are you sure you got the suppress call right? Isn't the first argument of constructor() supposed to be the class you would like to surpress the constructor in?
If using PowerMock for EasyMock you can do PowerMock.expectNew(CollaboratorToBeMocked.class, new Class[]{InjectedIntoCollaborator.class}, ...) where the Class[] is the parameter types of the constructor you're expecting to be called. This will resolve the ambiguity between the constructors.

Categories