How do I mock a static method that returns void with PowerMock?
Asked Answered
H

5

93

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.

Hooker answered 6/3, 2012 at 14:12 Comment(1)
Is the question for PowerMockito or PowerMock ? The title suggests PowerMock but looks like you r using PowerMockito.Rout
S
49

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

Searching answered 6/3, 2012 at 14:30 Comment(12)
unfortunately that won't work as when() only accepts a variable and StaticResource is a type. (StaticResource cannot be resolved to a variable)Hooker
Oh yeah sorry, you are correct my code is wrong, I'm to acustomed to non static mocks. Anyway I updated my ansswer to reflect the correct syntax.Searching
Thanks! So having static helper methods that have no dependencies is a bad idea? Of course I could just inject and object that does the work but it feels like it makes sense to put workers that have no dependencies in a static object to signify their independence..Hooker
What I meant is if your static helper methods need to be mocked, then you may seriously consider injecting a collaborator. A contrario you never need to mock StringUtils, Iterables, or anything else. Also don't forget we are using an object oriented language, it's all about messaging between objects (quoting Alan Kay). If you are interested, there's a great book : Growing Object Oriented Software Guided by Tests. Regards :)Searching
The leading doNothing() call is redundant. You only need doThrow(new Exception()).when(StaticResource.class); on that line.Datary
@MattLachman Thanks I spotted an unclear use of the API. The line of code in the answer will make the mock do nothing on the first call, then on the second call the mock will throw an exception. You are indeed right: by default on mocks methods do nothing by default (if the default is not changed at mock creation). That being said, it can a good idea to even write the doNothing behavior for documenting purpose of the collaborator in the test, of course this depends on the test and left at the judgment of the coder.Searching
this still doesn't work. when i attempt PowerMockito.verifyStatic(times(4)) it always passes, whether i say times(0), times(1), etc.Reynalda
@Reynalda verifyStatic is not about stubbing but about verifying calls, if you have an example I may help you.Searching
@Brice thanks i figured it out, the documentation wasn't clear that you had to invoke the expected call on the mocked static object.Reynalda
I am using mockito-inline lib version 3.8.0 without Powermock. Mocking class gives an exception: doNothing().when(A.class); - org.mockito.exceptions.misusing.NotAMockException: Argument passed to when() is not a mock! Example of correct stubbing: doThrow(new RuntimeException()).when(mock).someMethod();Zygote
@Zygote doNothing().when(A.class) looks incorrect as this code is passing A.class to mockito, which is indeed not a (Mockito) mock. The error message gives the correct syntax, but you might need a specific setup to use static mocking, I'll update my answer.Searching
Thank you @Brice. It worked by providing method name: try (MockedStatic<A> AObj = Mockito.mockStatic(A.class)){ A.methodName();} Although I agree on your comment on not mocking static methods.Zygote
I
100

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();
Ichthyic answered 2/7, 2013 at 8:10 Comment(4)
Being able to do this is pretty cool as it lets you do stuff like mocking Thread.sleep(long millis) to sleep for a different amount of time/less time/no time at all!Winters
Is there a way to avoid using strings for the methods - as "getResource" in your example?Denicedenie
@CasperThuleHansen you can potentially use reflection and get method name(s)Dincolo
the last part of the above method are the parameters and can more than one as needed separated by comma.Herringbone
S
49

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

Searching answered 6/3, 2012 at 14:30 Comment(12)
unfortunately that won't work as when() only accepts a variable and StaticResource is a type. (StaticResource cannot be resolved to a variable)Hooker
Oh yeah sorry, you are correct my code is wrong, I'm to acustomed to non static mocks. Anyway I updated my ansswer to reflect the correct syntax.Searching
Thanks! So having static helper methods that have no dependencies is a bad idea? Of course I could just inject and object that does the work but it feels like it makes sense to put workers that have no dependencies in a static object to signify their independence..Hooker
What I meant is if your static helper methods need to be mocked, then you may seriously consider injecting a collaborator. A contrario you never need to mock StringUtils, Iterables, or anything else. Also don't forget we are using an object oriented language, it's all about messaging between objects (quoting Alan Kay). If you are interested, there's a great book : Growing Object Oriented Software Guided by Tests. Regards :)Searching
The leading doNothing() call is redundant. You only need doThrow(new Exception()).when(StaticResource.class); on that line.Datary
@MattLachman Thanks I spotted an unclear use of the API. The line of code in the answer will make the mock do nothing on the first call, then on the second call the mock will throw an exception. You are indeed right: by default on mocks methods do nothing by default (if the default is not changed at mock creation). That being said, it can a good idea to even write the doNothing behavior for documenting purpose of the collaborator in the test, of course this depends on the test and left at the judgment of the coder.Searching
this still doesn't work. when i attempt PowerMockito.verifyStatic(times(4)) it always passes, whether i say times(0), times(1), etc.Reynalda
@Reynalda verifyStatic is not about stubbing but about verifying calls, if you have an example I may help you.Searching
@Brice thanks i figured it out, the documentation wasn't clear that you had to invoke the expected call on the mocked static object.Reynalda
I am using mockito-inline lib version 3.8.0 without Powermock. Mocking class gives an exception: doNothing().when(A.class); - org.mockito.exceptions.misusing.NotAMockException: Argument passed to when() is not a mock! Example of correct stubbing: doThrow(new RuntimeException()).when(mock).someMethod();Zygote
@Zygote doNothing().when(A.class) looks incorrect as this code is passing A.class to mockito, which is indeed not a (Mockito) mock. The error message gives the correct syntax, but you might need a specific setup to use static mocking, I'll update my answer.Searching
Thank you @Brice. It worked by providing method name: try (MockedStatic<A> AObj = Mockito.mockStatic(A.class)){ A.methodName();} Although I agree on your comment on not mocking static methods.Zygote
G
21

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();
Goncourt answered 4/5, 2015 at 12:30 Comment(1)
Will it work for multiple methods of StaticClass.class, like StaticClass.method(); StaticClass.method1(); StaticClass.method2();Hetti
J
7

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);
Jeffjeffcoat answered 7/7, 2016 at 8:9 Comment(0)
S
2

You can use mockitoStatic for mocking static void methods using then(invocationOnMock -> null), for ex.:

@Test
void testStaticVoidMethod() {
        try (MockedStatic<FileUtils> mockedFileUtils = mockStatic(FileUtils.class)) {
            mockedFileUtils.when(() -> FileUtils.writeByteArrayToFile(any(), any())).then(invocationOnMock -> null);
            assertDoesNotThrow(() -> FileUtils.writeByteArrayToFile(new File("test.txt"), new byte[0]));
        }
    }
Shoebill answered 24/4, 2023 at 12:36 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.