Powermockito Mock Single Static Method and Return Object

PowerMockito mock single static method and return object inside another static method

I found the solution in SOF in somebody's post.

In my case, I have used same partial mock of PowerMockito as below.

PowerMockito.stub(PowerMockito.method(OpenPgpUtility.class, "readPublicKey", InputStream.class)).toReturn(mockPGPPublicKey);

which letting me to mock readPublicKey() but an actual call to encrypt()

How to mock just one static method in a class using Mockito?

By default all methods are mocked. However, using Mockito.CALLS_REAL_METHODS you can configure the mock to actually trigger the real methods excluding only one.

For example given the class Sample:

class Sample{
static String method1(String s) {
return s;
}
static String method2(String s) {
return s;
}
}

If we want to mock only method1:

@Test
public void singleStaticMethodTest(){
try (MockedStatic<Sample> mocked = Mockito.mockStatic(Sample.class,Mockito.CALLS_REAL_METHODS)) {
mocked.when(() -> Sample.method1(anyString())).thenReturn("bar");
assertEquals("bar", Sample.method1("foo")); // mocked
assertEquals("foo", Sample.method2("foo")); // not mocked
}
}

Be aware that the real Sample.method1() will still be called. From Mockito.CALLS_REAL_METHODS docs:

This implementation can be helpful when working with legacy code. When
this implementation is used, unstubbed methods will delegate to the
real implementation. This is a way to create a partial mock object
that calls real methods by default.
...

Note 1: Stubbing partial mocks using
when(mock.getSomething()).thenReturn(fakeValue) syntax will call the
real method. For partial mock it's recommended to use doReturn
syntax.

So if you don't want to trigger the stubbed static method at all, the solution would be to use the syntax doReturn (as the doc suggests) but for static methods is still not supported:

@Test
public void singleStaticMethodTest() {
try (MockedStatic<Sample> mocked = Mockito.mockStatic(Sample.class,Mockito.CALLS_REAL_METHODS)) {
doReturn("bar").when(mocked).method1(anyString()); // Compilation error!
//...
}
}

About this there is an open issue, in particular check this comment.

PowerMock, mock a static method, THEN call real methods on all other statics

What are you looking for is called partial mocking.

In PowerMock you can use mockStaticPartial method.

In PowerMockito you can use stubbing, which will stub only the method defined and leave other unchanged:

PowerMockito.stub(PowerMockito.method(StaticUtilClass.class, "someStaticMethod")).toReturn(5);

also don't forget about the

@PrepareForTest(StaticUtilClass.class)

PowerMockito mockStatic gives MissingMethodInvocationException

I solved it following this, all other solutions didn't work for me. It is difficult to search for this solution, since there are too many on SO on the same.

PowerMockito mock single static method and return object inside another static method , PowerMock, mock a static method, THEN call real methods on all other statics

@RunWith(PowerMockRunner.class)
@PrepareForTest({Base64.class})
public class BqClientFactoryTest {
@Test
public void testGetBigQueryClient() throws Exception {
Base64.Decoder mockDecoder = mock(Base64.Decoder.class);
stub(method(Base64.class, "getDecoder")).toReturn(mockDecoder);

Static mock failing on JDK 17

The difference stems from the fact that JDK 17 no longer calls Clock.systemUTC() in implementation of Instant.now()

Please compare:

JDK 17:

public static Instant now() {
return Clock.currentInstant();
}

JDK 15:

public static Instant now() {
return Clock.systemUTC().instant();
}

If you insist on mocking static methods, you could stub Instant.now(), not Clock.systemUTC() - thus you don't rely on the implementation of Instant.now()

As discussed in the comments in under your post, this is not the recommended approach - class Clock was designed specifically to make time-handling code easier to test, use a Clock in your code instead of calling Instant.now()

@Test
void mockStaticClock() {
final Instant instantExpected = Instant.parse("2022-03-10T10:15:30Z");

try (final MockedStatic<Instant> instantMock = mockStatic(Instant.class)) {
instantMock.when(Instant::now).thenReturn(instantExpected);
final Instant now = Instant.now();
assertEquals(instantExpected, now);
}
}

How do I mock a static method call from a nother static method in the same class?

Starting from the docs, with some minor tweaks, you can either mock or spy the static method, depending on what you need (spying seems a bit less verbose but has different syntax). You can find below a sample for both, based on PowerMockito 1.7.3 & Mockito 1.10.19.

Given the following simple class with the required 2 static methods:

public class ClassWithStaticMethods {

public static String doSomething() {
throw new UnsupportedOperationException("Nope!");
}

public static String callDoSomething() {
return doSomething();
}

}

You can do something like:

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.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.powermock.api.mockito.PowerMockito.*;

// prep for the magic show
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassWithStaticMethods.class)
public class ClassWithStaticMethodsTest {

@Test
public void shouldMockStaticMethod() {
// enable static mocking
mockStatic(ClassWithStaticMethods.class);

// mock the desired method
when(ClassWithStaticMethods.doSomething()).thenReturn("Did something!");

// can't use Mockito.CALLS_REAL_METHODS, so work around it
when(ClassWithStaticMethods.callDoSomething()).thenCallRealMethod();

// validate results
assertThat(ClassWithStaticMethods.callDoSomething(), is("Did something!"));
}

@Test
public void shouldSpyStaticMethod() throws Exception {
// enable static spying
spy(ClassWithStaticMethods.class);

// mock the desired method - pay attention to the different syntax
doReturn("Did something!").when(ClassWithStaticMethods.class, "doSomething");

// validate
assertThat(ClassWithStaticMethods.callDoSomething(), is("Did something!"));
}

}


Related Topics



Leave a reply



Submit