Powermock throws InvalidUseOfMatchersException when mocking private method - java

I'm new to Powermock. Yesterday I watched a video about using Powermock, I follow their code and have a demo test program below. When I run the test
package myPackage;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
public class Test1{
#Test
public void testPrivateMethod() throws Exception {
DemoService mockDemoService = PowerMockito.spy(new DemoService());
PowerMockito.when(
mockDemoService,
"privateMethod",
ArgumentMatchers.any(String.class)
).then(invocation -> invocation.getArgument(0) + "_private_mock");
Assert.assertEquals(mockDemoService.dependentMethod("LoveTest"), "3000LoveTest_private_mock");
}
}
class DemoService {
private String privateMethod(String input) {
return input + "_private";
}
public String dependentMethod(String input) {
return 3000 + privateMethod(input);
}
}
It throw exception in the log below
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced or misused argument matcher detected here:
-> at myPackage.Test1.testPrivateMethod(Test1.java:19)
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))
This message may appear after an NullPointerException if the last matcher is returning an object
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
when(mock.get(any())); // bad use, will raise NPE
when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
I have some basic knowledge about Mockito, the code is somewhat similar to Mockito unit test (Mockito.spy and Mockito.when) but not work as expected. I don't know what's wrong with the code, why the exception InvalidUseOfMatchersException is thrown. Please help me, thank you.

Your code is missing #PrepareForTest. Powermock has to manipulate the byte-code of target mocking class, so you have to provide a path to it.
#RunWith(PowerMockRunner.class)
#PrepareForTest(DemoService.class)
public class Test1{
...

here ArgumentMatchers.any(String.class)
instead use ArgumentMatchers.anyString()

Related

Cannot Mock RandomStringUtils Class method random

I am using RandomStringUtils class from apache commons lang3 library. I am facing issue while mocking the random method of it.
below is my example class with simple method generatePassword.
public class Example() {
public String generatePassword() {
final String randomDevicePass = RandomStringUtils.random(10, "abcdefghijklmnopqrstuvwxyz");
System.out.println(randomDevicePass)
return randomDevicePass;
}
}
below is my Test Class, by which I am running the test case.
#RunWith(MockitoJUnitRunner.class)
public class ExampleTest() {
#InjectMocks
private Example Example;
#Mock
RandomStringutils randomStringutils;
#Test
public void givenCharacters_returnStringPassword() {
Mockito.when(randomStringUtils.random(Mockito.anyInt(),Mockito.anyString())).thenReturn("asdf");
Assertions.assertEquals("asdf", example.generatePassword());
}
}
It gives below error:
Misplaced or misused argument matcher detected here:
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))
This message may appear after an NullPointerException if the last matcher is returning an object
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
when(mock.get(any())); // bad use, will raise NPE
when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced or misused argument matcher detected here:
I am not sure how to mock the Java inbuilt apache commons library class. not sure can we use spy? or something ...can anyone helps me on this ?
Thanks in advance
It is usually somewhat of a code smell whenever you need to mock a static method. However, there are ways of doing it within the Mockito library.
First, add a file to your test resources directory in a new folder mockito-extensions. The file name should be org.mockito.plugins.MockMaker. The file needs to have the single line: mock-maker-inline
Then you are ready to add a static mock through Mockito.mockStatic like this:
try (MockedStatic<RandomStringUtils> utils = Mockito.mockStatic(RandomStringUtils.class)) {
utils.when(() -> RandomStringUtils.random(Mockito.anyInt(), Mockito.anyString())).thenReturn("asdf");
Assertions.assertEquals("asdf", example.generatePassword());
}

Junit 5 and Mockito 3: UnnecessaryStubbingException not thrown when injecting #Mock's through constructor

Looking at the two test classes below I assume the same behavior from them: to have an UnnecessaryStubbingException thrown. However MyTest2 does not. The MockitoExtension class should have strictness set to strict stubs by default. I can't seem to find any documented information about this behavior and I really want to understand it.
I prefer to write my tests as MyTest2 because I like to have final fields wherever possible, though I also really enjoy the strict stubs check done by Mockito.. Please help my understand the difference between the two tests.
package example;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
class MyTest {
#Mock
List<Integer> integerList;
#Test
void test() {
Mockito.when(integerList.size()).thenReturn(10);
System.out.println("Do something not involving list");
Assertions.assertTrue(true);
}
}
#ExtendWith(MockitoExtension.class)
class MyTest2 {
final List<Integer> integerList;
MyTest2(#Mock List<Integer> integerList) {
this.integerList = integerList;
}
#Test
void test() {
Mockito.when(integerList.size()).thenReturn(10);
System.out.println("Do something not involving list");
Assertions.assertTrue(true);
}
}
I found the reason in the mockito documentation:
Mockito JUnit Runner triggers UnnecessaryStubbingException only when none of the test methods use the stubbings. This means that it is ok to put default stubbing in a 'setup' method or in test class constructor. That default stubbing needs to be used at least once by one of the test methods.
If you do not want the exception to be thrown for the MyTest class, you can use Mockito.lenient or MockitoSettings. But I guess it is not possible to activate the exception for the MyTest2 class.

Is it possible to mock a static void method in powermock [duplicate]

I have a few static util methods in my project, some of them just pass or throw an exception. There are a lot of examples out there on how to mock a static method that has a return type other than void. But how can I mock a static method that returns void to just "doNothing()"?
The non-void version uses these lines of code:
#PrepareForTest(StaticResource.class)
...
PowerMockito.mockStatic(StaticResource.class);
...
Mockito.when(StaticResource.getResource("string")).thenReturn("string");
However if applied to a StaticResources that returns void, the compile will complain that when(T) is not applicable for void...
Any ideas?
A workaround would probably be to just have all static methods return some Boolean for success but I dislike workarounds.
You can stub a static void method like this:
PowerMockito.doNothing().when(StaticResource.class, "getResource", anyString());
Although I'm not sure why you would bother, because when you call mockStatic(StaticResource.class) all static methods in StaticResource are by default stubbed
More useful, you can capture the value passed to StaticResource.getResource() like this:
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
PowerMockito.doNothing().when(
StaticResource.class, "getResource", captor.capture());
Then you can evaluate the String that was passed to StaticResource.getResource like this:
String resourceName = captor.getValue();
Since Mockito 3.4.0, an experimental API was introduced to mock static methods.
The following example code has been tested with Mockito 4.3.1 (testImplementation("org.mockito:mockito-inline:4.3.1), and JUnit Jupiter 5.8.2, OpenJDK 11.
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.util.UUID;
public class StaticMockTest {
#Test
void showCaseStaticMock() {
try (MockedStatic<StaticMockTest> staticMock = Mockito.mockStatic(StaticMockTest.class)) {
staticMock.when(StaticMockTest::getUUIDValue).thenReturn("Mockito");
Assertions.assertEquals("Mockito", StaticMockTest.getUUIDValue());
}
// Regular UUID
UUID.fromString(StaticMockTest.getUUIDValue());
}
public static String getUUIDValue() {
return UUID.randomUUID().toString();
}
}
Previous Answer, probably Mockito 1.x/2.x with Powermock 1.x/2.x
You can do it the same way you do it with Mockito on real instances. For example you can chain stubs, the following line will make the first call do nothing, then second and future call to getResources will throw the exception :
// the stub of the static method
doNothing().doThrow(Exception.class).when(StaticResource.class);
StaticResource.getResource("string");
// the use of the mocked static code
StaticResource.getResource("string"); // do nothing
StaticResource.getResource("string"); // throw Exception
Thanks to a remark of Matt Lachman, note that if the default answer is not changed at mock creation time, the mock will do nothing by default. Hence writing the following code is equivalent to not writing it.
doNothing().doThrow(Exception.class).when(StaticResource.class);
StaticResource.getResource("string");
Though that being said, it can be interesting for colleagues that will read the test that you expect nothing for this particular code. Of course this can be adapted depending on how is perceived understandability of the test.
By the way, in my humble opinion you should avoid mocking static code if your crafting new code. At Mockito we think it's usually a hint to bad design, it might lead to poorly maintainable code. Though existing legacy code is yet another story.
Generally speaking if you need to mock private or static method, then this method does too much and should be externalized in an object that will be injected in the tested object.
Hope that helps.
Regards
In simpler terms,
Imagine if you want mock below line:
StaticClass.method();
then you write below lines of code to mock:
PowerMockito.mockStatic(StaticClass.class);
PowerMockito.doNothing().when(StaticClass.class);
StaticClass.method();
To mock a static method that return void for e.g. Fileutils.forceMKdir(File file),
Sample code:
File file =PowerMockito.mock(File.class);
PowerMockito.doNothing().when(FileUtils.class,"forceMkdir",file);

PowerMock not stubbing static method properly?

I'm trying to write a VERY simple test, using powermock and Robolectric. Here's my code:
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.robolectric.RobolectricTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
#RunWith(RobolectricTestRunner.class)
#PowerMockIgnore({ "org.mockito.*", "org.robolectric.*", "android.*" })
#PrepareForTest(BadStaticClass.class)
public class SomeActivityTest {
#Test
public void testSomething() {
PowerMockito.mockStatic(BadStaticClass.class);
Mockito.when(BadStaticClass.dontWantThisMethod()).thenReturn(false);
new SomeActivity().usesStatic();
}
}
Basically, i have a class, "SomeActivity", and it has a method that makes a call to BadStaticClass.dontWantThisMethod(). i want that static method to be stubbed out.
why is my code not working?
i kept getting errors like:
you are trying to stub a final method, you naughty developer!
which, i thought the whole point of PowerMock was to not see that.
According to the PowerMock API you have to include #RunWith(PowerMockRunner.class) for certain versions of JUnit, etc. However you also need to be using #RunWith(RobolectricTestRunner.class) and cannot specify more than one #RunWith on a Class.
So what to do?
I suspect you can keep your code above and introduce a JUnit #Rule (see: PowerMockRule docs) and also described in this similar post. Just be sure you check the versions of the Jars you are using so that they match those described in that other SO post. All too often things just won't work unless you get compatible versions, and it's not always obvious what versions are compatible.

Mockito Matcher parameters showing as undefined

I am trying to Mock a method contained in the Main class of an application. I'd like to test that when all parameters are submitted successfully, the application calls the correct method, uploadFiles. The when - thenReturn pair is shown below:
NrClient nrClient = (NrClient)Mockito.mock(NrClient.class);
Mockito.when(nrClient.uploadFiles("DF49ACBC8", anyList(), "dl")).thenReturn("");
This shows as a runtime exception: "The method anyString() is undefined for the type MainTest."
I have the imports:
import org.mockito.Mockito;
import org.mockito.Matchers;
So why would this method be undefined? Is there an issue in my implementation?
I have also tried anyString() and anyInt() with the same result.
You should be getting it as a compile-time error, not an exception (unless the actual exception is that you've got an unresolved compile-time error).
Just importing org.mockito.Matchers means you can use the name Matchers to mean org.mockito.Matchers anywhere in the class. If you want to import the methods, you need a static wildcard import:
import static org.mockito.Matchers.*;
Or specific methods:
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.anyList;
Or you could just qualify the method name in the calling code instead:
Mockito.when(nrClient.uploadFiles("DF49ACBC8", Matchers.anyList(), "dl"))
.thenReturn("");
Use the below import
import static org.mockito.ArgumentMatchers.*;
Avoid to use Matchers class because it is now deprecated in order to avoid a name clash with Hamcrest org.hamcrest.Matchers class.

Categories