I am trying to capture the 'logError' method in a static class (in the sense of every method/field is static), and verify it has been called some number of times by other methods in the same class.
this method is:
public static void logError(Object message){
LOGGER.error(message); // static logger
}
my attempt to test it:
#Test
public void errLogTest() throws Exception{
PowerMockito.mockStatic(X.class);
PowerMockito.doNothing().when(X.class);
X.logError(Mockito.anyString());
X.open();
X.open(); //should log error for opening twice
PowerMockito.verifyStatic(Mockito.times(1));
}
My problem is, no matter how many times I specify, it passes. I removed mocking behavior and know for a fact the logger is called once, but I can have PowerMockito.verifyStatic(Mockito.times(9001)); instead and it still passes. How do I test this?
You're missing a line of code after verifyStatic. You're not telling PowerMock what to verify. You're also mocking all static methods of the class instead of just the one you don't want called.
#Test
public void errLogTest() throws Exception{
PowerMockito.spy(X.class); //Used to be: PowerMockito.mockStatic(X.class);
PowerMockito.doNothing().when(X.class);
X.logError(Mockito.anyString());
X.open();
X.open(); //should log error for opening twice
PowerMockito.verifyStatic(Mockito.times(1));
X.logError(Mockito.anyString()); //Now verifyStatic knows what to verify.
}
You may still need to do some debugging because, in my experience, setting up the expectations sometimes calls the underlying method anyway.
Here's the javadoc for spy: http://static.javadoc.io/org.powermock/powermock-api-mockito/1.5.4/org/powermock/api/mockito/PowerMockito.html#spy(java.lang.Class)
Here's the javadoc for verifyStatic: http://static.javadoc.io/org.powermock/powermock-api-mockito/1.5.4/org/powermock/api/mockito/PowerMockito.html#verifyStatic(org.mockito.verification.VerificationMode)
Related
I am new to Mockito and PowerMockito. I have a test method where I use PowerMockito to mock a static recursive method. I need to verify that particular method is invoked 2 times, but the test case fails. Also the actual method is not hit.
This is the code.
Testing method:
public class Util {
public static void methodToTest(String a, String b) {
..............
methodToTest(c, d);
}
}
Test case :
public void testMethodToTest() {
PowerMockito.mockStatic(Util.class);
Util.methodToTest(e, f);
verifyStatic(Util.class, Mockito.times(2));
Util.methodToTest(Matchers.anyString(), Matchers.anyString());
}
But when I run the test it fails with the following error.
Wanted 2 times but was 1 time.
at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:182)
at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:164)
at org.powermock.core.MockGateway.methodCall(MockGateway.java:141)
Ideally with Util.methodToTest(e, f) call,it should call the actual methodToTest twice.
I debugged the code and then I noticed that Util.methodToTest(e, f) call does not go inside the actual method.
What is the issue in this code? How can I verify that this recursive method is getting called twice?
Powermock version - 1.7.4
The problem here is that you are invoking intercepted method from inside of spied/mocked object. Interception is made when call is made from the outside. So original call is "registered" but not the internal one.
I am not sure it is a bug or expected behavior, but I have ran into the same issue some time ago (but not with statics) and If I recall I redesigned the test.
I'm testing some methodA which has another one inside and I need to check that that methodB has not been called due to return.
If I run this test with debug, everything works correctly. But test fails as PowerMock runs it somewhere underhood.
My test:
#Test
public void incomingCall_dismissIncoming_incomingDataNull() throws Exception {
mIncomingCallData = null;
Whitebox.setInternalState(SUT, "mLastIncomingCallData", mIncomingCallData);
SUT.dismissIncoming();
verifyPrivate(SUT, times(0)).invoke("onIncomingCallDeclined");
}
The question is why is that and how can I test it? I know I don't need to test private methods, but I need it in this specific case.
static class Foo {
public void bar(int i) {}
}
#Test
public void foo() {
Foo f = Mockito.spy(new Foo());
f.bar(42);
Mockito.verify(f, Mockito.times(1)).bar(42);
f.bar(42);
Mockito.verify(f, Mockito.times(1)).bar(42);
}
causes org.mockito.exceptions.verification.TooManyActualInvocations (wanted 1 time, but was 2) on last line. Running it in debug shows, that InvocationMatcher ignores the fact that first invocation was already verified. And it does not depend on witch exactly matcher is passed into bar. Am I doing something wrong, or it is a bug of Mockito?
There is no bug. The implementors of the library thinks multiple invocations in a single test method is not a best practice. There two choices to overcome this issue:
Good one: use separate tests for each f.bar() invocations and test them independently.
Not a good one: use Mockito.reset(f) before the second invocation. It resets the state of the spied f; for instance if you have inserted a mock call like doThrow(new Exception).when(f).bar(45), it is reset after the reset() call. But the second verify works with times(1).
I'm trying to find methods like this:
#Test
public void testStuff()
{
doStuff();
doOtherStuff();
mockery.assertIsSatisfied();
}
The goal is to remove the mockery.assertIsSatisfied(). I can't just remove all calls to it because sometimes it's in the middle of a method or at the end of a loop, where it seems reasonable. Of course, we're using the JUnit #Rule to invoke this automatically, so it's redundant to have it at the end of every test.
I thought this would be the right template:
#Test
public void $testMethod$() throws Exception
{
$Statements$; // configured this as 1..many
mockery.assertIsSatisfied();
}
This matches about 2 methods out of the 400+ usages of that method. Randomly picking some of the other usages of that method, I see that others should have matched the pattern too. (I can't figure out what is common between the ones which do match. They're both try blocks, but so are some of the ones which don't match.)
So what is the right way to do this?
Edit: I just noticed I had hard-coded a throws Exception onto this one, so I re-executed the search without it, and that gives 0 results. In case anybody is wondering.
It's (currently) not possible to use a naked method as a pattern. To search for a method you need to surround it with a class like this:
class $Class$ {
#Test
public void $testMethod$() // 1..unlimited
{
$Statements$; // 1..unlimited
mockery.assertIsSatisfied();
}
}
Be sure that the method is also configured with occurrences 1..unlimited, or only one method per class will be found.
I am writing a unit test for a FizzConfigurator class that looks like:
public class FizzConfigurator {
public void doFoo(String msg) {
doWidget(msg, Config.ALWAYS);
}
public void doBar(String msg) {
doWidget(msg, Config.NEVER);
}
public void doBuzz(String msg) {
doWidget(msg, Config.SOMETIMES);
}
public void doWidget(String msg, Config cfg) {
// Does a bunch of stuff and hits a database.
}
}
I'd like to write a simple unit test that stubs the doWidget(String,Config) method (so that it doesn't actually fire and hit the database), but that allows me to verify that calling doBuzz(String) ends up executing doWidget. Mockito seems like the right tool for the job here.
public class FizzConfiguratorTest {
#Test
public void callingDoBuzzAlsoCallsDoWidget() {
FizzConfigurator fixture = Mockito.spy(new FizzConfigurator());
Mockito.when(fixture.doWidget(Mockito.anyString(), Config.ALWAYS)).
thenThrow(new RuntimeException());
try {
fixture.doBuzz("This should throw.");
// We should never get here. Calling doBuzz should invoke our
// stubbed doWidget, which throws an exception.
Assert.fail();
} catch(RuntimeException rte) {
return; // Test passed.
}
}
}
This seems like a good gameplan (to me at least). But when I actually go to code it up, I get the following compiler error on the 2nd line inside the test method (the Mockito.when(...) line:
The method when(T) in the type Mockito is not applicable for the arguments (void)
I see that Mockito can't mock a method that returns void. So I ask:
Am I approaching this test setup correctly? Or is there a better, Mockito-recommended, way of testing that doBuzz calls doWidget under the hood? And
What can I do about mocking/stubbing doWidget as it is the most critical method of my entire FizzConfigurator class?
I wouldn't use exceptions to test that, but verifications. And another problem is that you can't use when() with methods returning void.
Here's how I would do it:
FizzConfigurator fixture = Mockito.spy(new FizzConfigurator());
doNothing().when(fixture).doWidget(Mockito.anyString(), Mockito.<Config>any()));
fixture.doBuzz("some string");
Mockito.verify(fixture).doWidget("some string", Config.SOMETIMES);
This isn't a direct answer to the question, but I ran across it when trying to troubleshoot my problem and haven't since found a more relevant question.
If you're trying to stub/mock an object marked as Spy, Mockito only picks up the stubs if they're created using the do...when convention as hinted at by JB Nizet:
doReturn(Set.of(...)).when(mySpy).getSomething(...);
It wasn't being picked up by:
when(mySpy.getSomething(...)).thenReturn(Set.of(...));
Which matches the comment in MockHandlerImpl::handle:
// stubbing voids with doThrow() or doAnswer() style
This is a clear sign that doWidget method should belong to another class which FizzConfigurator would depend on.
In your test, this new dependency would be a mock, and you could easily verify if its method was called with verify.
In my case, for the method I was trying to stub, I was passing in incorrect matchers.
My method signature (for the super class method I was trying to stub): String, Object.
I was passing in:
myMethod("string", Mockito.nullable(ClassType.class)) and getting:
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, which is not supported
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
When using a matcher in another parameter, we also need to use one for the string:
myMethod(eq("string"), Mockito.nullable(ClassType.class))
Hope this helps!