Mocking behaviour resets after each test with PowerMock - java

I'm writing unit tests using PowerMock, mocking behaviour of some util classes. Defining behaviour once for test class (by #BeforeClass annotation) causes:
first test invocation to return mocked value
second test invocation to return real method return value
Sample code:
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest( {A.class, B.class})
public class TestMockedMethods {
private static B b;
#BeforeClass
public static void setUp() {
PowerMockito.mockStatic(A.class);
PowerMockito.when(A.getVal()).thenReturn("X");
b = PowerMockito.mock(B.class);
PowerMockito.when(b.getVal()).thenReturn("Y");
}
#Test
public void test1() { // PASS
Assert.assertEquals("X", A.getVal());
Assert.assertEquals("Y", b.getVal());
}
#Test
public void test2() { // FAIL
Assert.assertEquals("X", A.getVal()); // actual="A"
Assert.assertEquals("Y", b.getVal()); // actual="B"
}
}
class A {
static String getVal() {
return "A";
}
}
class B {
String getVal() {
return "B";
}
}
Any ideas why second test is failing?

The method PowerMockito.mockStatic(...) invokes MockCreator.mock(...). This method regsiters a Runnable that will be executed after each test :
MockRepository.addAfterMethodRunner(new MockitoStateCleaner());
This runnable cleans the internal state of Mockito :
private static class MockitoStateCleaner implements Runnable {
public void run() {
clearMockProgress();
clearConfiguration();
}
private void clearMockProgress() {
clearThreadLocalIn(ThreadSafeMockingProgress.class);
}
private void clearConfiguration() {
clearThreadLocalIn(GlobalConfiguration.class);
}
private void clearThreadLocalIn(Class<?> cls) {
Whitebox.getInternalState(cls, ThreadLocal.class).set(null);
final Class<?> clazz = ClassLoaderUtil.loadClass(cls, ClassLoader.getSystemClassLoader());
Whitebox.getInternalState(clazz, ThreadLocal.class).set(null);
}
}
So you should execute your setUp before each test.
#Before
public void setUp() {
PowerMockito.mockStatic(A.class);
PowerMockito.when(A.getVal()).thenReturn("X");
b = PowerMockito.mock(B.class);
PowerMockito.when(b.getVal()).thenReturn("Y");
}

Related

Unable to override static final variable of a final class using PowerMock

I'm trying to use PowerMock Whitebox setInternalState api to override a static final variable of a final class. But it doesn't seems to be working. Please see sample code below:
A final class with static final variable:
public final class BuildConfig {
public static final String BUILD_TYPE = "debug";
}
A helper class to return the above variable:
public class BuildConfigHelperClass {
public String getBuildType() {
return BuildConfig.BUILD_TYPE;
}
}
Test class
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.SuppressStaticInitializationFor;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import static org.junit.Assert.*;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
#RunWith(PowerMockRunner.class)
#SuppressStaticInitializationFor("BuildConfig")
#PrepareForTest({BuildConfigHelperClassTest.class, BuildConfigHelperClass.class, BuildConfig.class})
public class BuildConfigHelperClassTest {
private BuildConfigHelperClass subject;
#Before
public void setUp() {
subject = new BuildConfigHelperClass();
}
#Test
public void shouldReturnDebugBuildType() {
assertEquals("debug", subject.getBuildType());
}
#Test
public void shouldReturnProductionBuildType() {
mockStatic(BuildConfig.class);
Whitebox.setInternalState(BuildConfig.class, "BUILD_TYPE", "production");
assertEquals("production", subject.getBuildType());
}
}
In above test class, for second test subject.getBuildType() method should return "production" as I am overriding it through Whitebox, but it always fails because of return value i.e. "debug".
Can anyone please guide me on what I'm missing.
The compiler is optimizing the code, where this:
public class BuildConfigHelperClass {
public String getBuildType() {
return BuildConfig.BUILD_TYPE;
}
}
is essentially compiled to:
public class BuildConfigHelperClass {
public String getBuildType() {
return "debug";
}
}
so the unit test is running against compiled code which has no reference to BuildConfig.
Instead of referencing BUILD_TYPE directly, try adding a static getter:
public final class BuildConfig {
private static final String BUILD_TYPE = "debug";
public static final String getBuildType() {
return BUILD_TYPE;
}
}
Then the static method can be mocked:
#Test
public void shouldReturnProductionBuildType() {
mockStatic(BuildConfig.class);
// Whitebox.setInternalState(BuildConfig.class, "BUILD_TYPE", "production");
PowerMockito.when(BuildConfig.getBuildType()).thenReturn("production");
assertEquals("production", subject.getBuildType());
}
This test works on my local, although other compilers might still be able to optimize it away and break the test.

How do I mock an implementation class?

I have something like this:
public interface SomeInterface {
public String someMethod(String someArg1, String someArg2);
}
public class SomeInterfaceImpl {
#Override
public String someMethod(String someArg1, String someArg2) {
String response;
// a REST API call which fetches response (need to mock this)
return response;
}
}
public class SomeClass {
public int execute() {
int returnValue;
// some code
SomeInterface someInterface = new SomeInterfaceImpl();
String response = someInterface.someMethod("some1", "some2");
// some code
return returnValue;
}
}
I want to test the execute() method in SomeClass using JUnit. Since someMethod(String someArg1, String someArg2) calls a REST API, I want to mock someMethod to return some predefined response. But somehow, the real someMethod gets called instead of returning the predefined response. How do I make it work?
Here is what I have tried using Mockito and PowerMockito:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ SomeInterface.class, SomeInterfaceImpl.class, SomeClass.class })
public class SomeClassTest {
#Test
public void testExecute() {
String predefinedResponse = "Some predefined response";
int expectedReturnValue = 10;
SomeInterfaceImpl impl = PowerMockito.mock(SomeInterfaceImpl.class);
PowerMockito.whenNew(SomeInterfaceImpl.class).withAnyArguments().thenReturn(impl);
PowerMockito.when(impl.someMethod(Mockito.any(), Mockito.any())).thenReturn(predefinedResponse);
SomeClass someClass = new SomeClass();
int actualReturnValue = someClass.execute();
assertEquals(expectedReturnValue, actualReturnValue);
}
}
Here is an example of injecting dependencies without a framework:
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
interface SomeInterface {
String someMethod(String someArg1, String someArg2);
}
class SomeInterfaceImpl implements SomeInterface {
#Override
public String someMethod(String someArg1, String someArg2) {
String response;
response = "the answer.";// a REST API call which fetches response (need to mock this)
return response;
}
}
class SomeClass {
private final SomeInterface someInterface;
SomeClass(final SomeInterface someInterface) {
this.someInterface = someInterface;
}
public SomeClass() {
this(new SomeInterfaceImpl());
}
public int execute() {
int returnValue;
// some code
String response = someInterface.someMethod("some1", "some2");
returnValue = 42; // some code
return returnValue;
}
}
#RunWith(MockitoJUnitRunner.class)
class SomeClassTest {
private static final String SOME_PREDEFINED_RESPONSE = "Some predefined response";
#Mock
private SomeInterface someInterface;
#InjectMocks
private SomeClass underTest;
#Before
public void setup() {
when(someInterface.someMethod(anyString(), anyString())).thenReturn(SOME_PREDEFINED_RESPONSE);
}
#Test
public void testExecute() {
int expectedReturnValue = 42;
int actualReturnValue = underTest.execute();
assertEquals(expectedReturnValue, actualReturnValue);
}
}
You don't have to do that.
You change your method under test to NOT call new directly.
Instead you use dependency injection for example.
Yes, this could be done with Powermock, but please believe me: doing so is the wrong approach!
This answer is very similar to answer posted by Andreas, the only difference being you can run this with #RunWith(SpringRunner.class) and it will avoid problems with bean instantiation and extra configuration. Avoid Powermocks and use it only when you need to mock static classes.
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
interface SomeInterface {
String someMethod(String someArg1, String someArg2);
}
class SomeInterfaceImpl implements SomeInterface {
#Override
public String someMethod(String someArg1, String someArg2) {
String response;
response = "the answer.";// a REST API call which fetches response (need to mock this)
return response;
}
}
class SomeClass {
private final SomeInterface someInterface;
SomeClass(final SomeInterface someInterface) {
this.someInterface = someInterface;
}
public SomeClass() {
this(new SomeInterfaceImpl());
}
public int execute() {
int returnValue;
// some code
String response = someInterface.someMethod("some1", "some2");
returnValue = 42; // some code
return returnValue;
}
}
#RunWith(MockitoJUnitRunner.class)
class SomeClassTest {
private static final String SOME_PREDEFINED_RESPONSE = "Some predefined response";
#Mock
private SomeInterface someInterface;
#InjectMocks
private SomeClass underTest;
#Before
public void setup() {
when(someInterface.someMethod(anyString(), anyString())).thenReturn(SOME_PREDEFINED_RESPONSE);
}
#Test
public void testExecute() {
int expectedReturnValue = 42;
int actualReturnValue = underTest.execute();
assertEquals(expectedReturnValue, actualReturnValue);
}
}

How to mock only one static method and test the other

#Mocked Provider provider;
public static class Provider {
public static List<Integer> getStaticList() {
return new ArrayList<>();
}
public static List<Integer> test() {
return getStaticList();
}
}
#Test
public void testStatic() {
ArrayList<Object> list = new ArrayList<>();
list.add(1);
new Expectations() {
{
Provider.getStaticList();
result = list;
}
};
assertThat(Provider.test(), JUnitMatchers.hasItem(1));
}
I want to mock (with JMockit) one static method that is called within another one. How can I do that? The above test fails. The real Provider.test method is never called.
The code below changes the behaviour of doSomething static method only, without affecting other static methods.
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest({Foo.class})
public class Snipets {
#Test
public void hoge() throws Exception {
PowerMockito.spy(Foo.class);
PowerMockito.when(Foo.class, "doSomething").thenReturn("dummy");
String actual = Foo.doSomething();
assertEquals("dummy", actual);
}
}
Foo.java
public class Foo {
public static String doSomething() {
return "foo";
}
}
Source: https://gist.github.com/mid0111/8859159
You can use partial mocking:
#Test
public void testStatic() {
new Expectations(Provider.class) {{ Provider.getStaticList(); result = 1; }};
List<Integer> test = Provider.test();
assertTrue(test.contains(1));
}
(With no "#Mocked Provider" field for the test above.)
I used a very simple method of writing a conditional answer like this:
PowerMockito.mockStatic(<MyMockedClass>.class, invocation -> {
if (invocation.getMethod().getName().equals("<methodToMockName>")) {
return <mockedValue>;
}
return invocation.callRealMethod();
});

PowerMockito: mocking private method and get a value without accessing it

I'm writing java unit test for a legacy code and I'm new to this area as well. I have to test following scenario (write unit test case for the testableMethod()). So, without executing code inside the getMode() method, I want to get a value for the mode variable.
Class A{
public boolean testableMethod()
{
//code
......
int mode = getMode();
......
//do something with mode
return X;
}
private int getMode()
{
return ComplexCalls(ComplexMethodCalls(), more());
}
}
I've tried to do it using PowerMockito without getting success. It is possible to mock these kind of scenario with PowerMockito?.
You can with a PowerMockito spy:
public class A {
public boolean testableMethod() {
return getMode() == 1;
}
private int getMode() {
return 5;
}
}
import static org.junit.Assert.assertTrue;
import static org.powermock.api.mockito.PowerMockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.spy;
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(A.class)
public class ATest {
#Test
public void testableMethod_should_do_this() throws Exception {
A a = spy(new A());
doReturn(1).when(a, "getMode");
assertTrue(a.testableMethod());
}
}
See all this full example of partial mocking of a private method

Java JUnit framework #BeforeClass and (Power)Mockito for a static method [duplicate]

I'm writing unit tests using PowerMock, mocking behaviour of some util classes. Defining behaviour once for test class (by #BeforeClass annotation) causes:
first test invocation to return mocked value
second test invocation to return real method return value
Sample code:
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest( {A.class, B.class})
public class TestMockedMethods {
private static B b;
#BeforeClass
public static void setUp() {
PowerMockito.mockStatic(A.class);
PowerMockito.when(A.getVal()).thenReturn("X");
b = PowerMockito.mock(B.class);
PowerMockito.when(b.getVal()).thenReturn("Y");
}
#Test
public void test1() { // PASS
Assert.assertEquals("X", A.getVal());
Assert.assertEquals("Y", b.getVal());
}
#Test
public void test2() { // FAIL
Assert.assertEquals("X", A.getVal()); // actual="A"
Assert.assertEquals("Y", b.getVal()); // actual="B"
}
}
class A {
static String getVal() {
return "A";
}
}
class B {
String getVal() {
return "B";
}
}
Any ideas why second test is failing?
The method PowerMockito.mockStatic(...) invokes MockCreator.mock(...). This method regsiters a Runnable that will be executed after each test :
MockRepository.addAfterMethodRunner(new MockitoStateCleaner());
This runnable cleans the internal state of Mockito :
private static class MockitoStateCleaner implements Runnable {
public void run() {
clearMockProgress();
clearConfiguration();
}
private void clearMockProgress() {
clearThreadLocalIn(ThreadSafeMockingProgress.class);
}
private void clearConfiguration() {
clearThreadLocalIn(GlobalConfiguration.class);
}
private void clearThreadLocalIn(Class<?> cls) {
Whitebox.getInternalState(cls, ThreadLocal.class).set(null);
final Class<?> clazz = ClassLoaderUtil.loadClass(cls, ClassLoader.getSystemClassLoader());
Whitebox.getInternalState(clazz, ThreadLocal.class).set(null);
}
}
So you should execute your setUp before each test.
#Before
public void setUp() {
PowerMockito.mockStatic(A.class);
PowerMockito.when(A.getVal()).thenReturn("X");
b = PowerMockito.mock(B.class);
PowerMockito.when(b.getVal()).thenReturn("Y");
}

Categories

Resources