I am trying to write a TestNg test using Powermock to mock a static function call.
My test code is :
import static org.easymock.EasyMock.expect;
import static org.powermock.api.easymock.PowerMock.mockStatic;
import static org.powermock.api.easymock.PowerMock.replay;
import static org.powermock.api.easymock.PowerMock.verify;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.testng.Assert;
import org.testng.annotations.Test;
#PrepareForTest(TestStringProvider.class)
public class TryPowerMock {
public void test() {
String string = TestStringProvider.getString();
Assert.assertEquals(string, "testString");
}
#Test
public void tryPowerMock() {
mockStatic(TestStringProvider.class);
expect(TestStringProvider.getString()).andReturn("testString");
replay(TestStringProvider.class);
test();
verify(TestStringProvider.class);
}
}
Class with static function:
public class TestStringProvider {
public static String getString(){
return "WHY AM I CALLED, I AM SUPPOSED TO BE MOCKED";
}
}
Running this test gives me following exception,
FAILED: tryPowerMock
java.lang.IllegalStateException: no last call on a mock available
at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:520)
at org.easymock.EasyMock.expect(EasyMock.java:498)
at com.archit.learn.powermock.TryPowerMock.tryPowerMock(TryPowerMock.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Explored some more and found the solution myself.
I had to extend my unit test from class PowerMockTestCase
Related
I am writing a unit test to mock a static method in the verticle but getting ClassNotPreparedException always. I think that its only possible to mock this way if only the class is static, but i have non static class. What am i missing?
I have tried various solutions like using #rule or #PowerMockIgnore
//myVerticleTest.java
package com.blabla.me.verticles;
import static com.google.common.truth.Truth.assertThat;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import io.vertx.core.Vertx;
import io.vertx.junit5.VertxTestContext;
import io.vulpx.VulpxTestBase;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.junit.runner.RunWith;
import com.blabla.me.verticles.AdditionalInformationCardVerticle;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.junit.Rule;
import com.blabla.me.verticles.st;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ st.class })
#PowerMockIgnore({"org.mockito.*"})
public class myVerticleTest extends VulpxTestBase {
#Rule public PowerMockRule rule = new PowerMockRule();
private Vertx vertx;
private AdditionalInformationCardVerticle dummy;
#BeforeEach
#PrepareForTest({ st.class })
public void setUp(VertxTestContext testContext) throws Exception {
vertx = Vertx.vertx();
try {
PowerMockito.mockStatic(st.class);
PowerMockito.when(st.createClient()).thenReturn("kk");
//deploying verticle
dummy = new AdditionalInformationCardVerticle();
vertx.deployVerticle(dummy, testContext.completing());
} catch (Exception e) {
System.out.println("heyyy eroorrr : " + e);
}
}
#Test
#PrepareForTest({ st.class })
public void justnormaltest() {
cla ownclass = new cla();
String k = ownclass.createfromclass();
assertThat("kk").isEqualTo(k);
}
}
// st.java
public class st {
public static String createClient() {
return "kk";
}
}
// cla.java
public class cla {
public String createfromclass() {
return st.createClient();
}
}
I expect it to run the assertion but i always get below excpetion:
"org.powermock.api.mockito.ClassNotPreparedException:
The class com.sap.me.verticles.st not prepared for test.
To prepare this class, add class to the '#PrepareForTest' annotation.
In case if you don't use this annotation, add the annotation on class or method level. "
Here:
#PrepareForTest({ st.class })
That one goes to exactly one place: in front of your test class public class myVerticleTest.
And hint: instead of adding more and more "things" to not working code: pick any good documentation, and try to follow that to the last ; in the example code (instead of assuming that adding more and more things here or there would help).
One good starting point: the official documentation on static mocking.
And of course, the usual caveat: consider not learning about PowerMock in the first place. Instead focus on writing "easy to test" code. Far too often, people think PowerMock(ito) is the answer to their problem. When their problem in reality is their inability to write "easy to test" production code.
How to mock getResourceAsStream in the static block?
I think it is untestable.
I reviewed SO and cannot find the answer. The closes-SO-post-here does not address the issue as the call to getResourceAsAStream in the post is not from a static block.
I tried PowerMock, and run into number of limitations. First if I want to mock SomeProperties.class.getResourceAsStream - the static block will execute, as I will need to refer to the class itself. I can suppress static block to prevent doing so, but this will prevent me from getting the static block to execute at all. The solution would be to postpone the execution of the static block until after someProperties.class.getResourceAsStream is mocked.
I do not think it is possible though.
It seems that this code is purely untestable;
Any other ideas?
Here is the code [and a link to GITHUB]:
package com.sopowermock1;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class SomeProperties {
private static Properties props = new Properties();
static {
InputStream is = SomeProperties.class.getResourceAsStream("/some.properties");
try {
props.load(is);
System.out.println("Properties.props.keySet() = " + props.keySet());
} catch (IOException e) {
// How test this branch???
System.out.println("Yes. We got here.");
throw new RuntimeException(e);
}
}
private SomeProperties() {}; // to makes life even harder...
public static String getVersion() {
return props.getProperty("version");
}
}
And here is the test GITHUB Link
package com.sopowermock1;
import java.io.InputStream;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import com.sopowermock1.SomeProperties;
#RunWith(PowerMockRunner.class)
#PrepareForTest(SomeProperties.class)
// This will prevent running static block completely:
// #SuppressStaticInitializationFor("com.sopowermock1.SomeProperties")
public class SomePropertiesTest {
#Mock
private static InputStream streamMock;
#Before
public void setUp() {
MockitoAnnotations.initMocks(SomeProperties.class);
System.out.println("test setUp");
}
#Test(expected = RuntimeException.class)
public void testStaticBlock() {
PowerMockito.mockStatic(SomeProperties.class); // this will mock all static methods (unwanted as we want to call getVersion)
// This will cause static block to be called.
PowerMockito.when(SomeProperties.class.getResourceAsStream("/some.properties")).thenReturn(streamMock);
SomeProperties.getVersion();
}
}
Any ideas?. Full GITHUB source is here.
as mention in How to mock getResourceAsStream method using PowerMockito and JUnit?, use Extract Delegate , then mock the delegate class such as XXStreamFetcher, and then you can test it.
Given this target code:
...
sessionWrapper.execute(arenaCreateCql, arenaGuid, arenaName, displayName, authorName, createdOn);
...
And Mockito code to validate that line:
...
#Captor
private ArgumentCaptor<Date> createdOnCaptor;
...
#Test
public void testThat_Execute_CreatesNewArena() throws Exception {
...
inOrder.verify(mockSessionWrapper).execute(
eq(arenaCreateCql), eq(testArenaGuid), eq(testArenaName), eq(testArenaDisplayName), eq(testAuthorName), createdOnCaptor.capture());
...
assertNotNull(createdOnCaptor.getValue());
}
This works using Mockito 1.9.5. When upgrading 1.10.8, the verify passes, but the getValue() fails with this error:
org.mockito.exceptions.base.MockitoException:
No argument value was captured!
You might have forgotten to use argument.capture() in verify()...
...or you used capture() in stubbing but stubbed method was not called.
Be aware that it is recommended to use capture() only with verify()
Edit to add MCVE. The following code runs green with Mockito 1.9.5, red with Mockito 1.10.8.
MockitoExample.java:
package org.makeyourcase.example;
import java.util.Date;
public class MockitoExample {
private MockitoExampleExecutor executor;
public void execute(){
executor.execute("var1", new Date());
}
}
MockitoExampleExecutor.java:
package org.makeyourcase.example;
public class MockitoExampleExecutor {
public void execute(Object... bindVariables){
}
}
MockitoExample_UT:
package org.makeyourcase.example;
import java.util.Date;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
#RunWith(MockitoJUnitRunner.class)
public class MockitoExample_UT {
#Mock
private MockitoExampleExecutor mockitoExampleExecutor;
#Captor
private ArgumentCaptor<Date> dateCaptor;
#InjectMocks
private MockitoExample subject;
#Test
public void testThat_Execute_InvokesCalendar() throws Exception {
subject.execute();
verify(mockitoExampleExecutor).execute(eq("var1"), dateCaptor.capture());
assertNotNull(dateCaptor.getValue());
}
}
One other piece of info came to light as a result of creating the MCVE - the test works fine if the Date is the only element passed for bindVariables. That is, remove "var1" from target and test code, then the test runs fine under 1.9.5 and 1.10.8. Also, it doesn't matter that the captor is for a Date. The same issue occurs if the parameter is of another type, such as Integer.
Thanks, this is probably a bug, I've created the report on GH-188.
Not sure when it will be fixed though. Fixed in GH-211.
I was trying to mock my test suites. My test framework creates test cases by scanning test files on disk. So each time the test cases are dynamically created.
I was trying to use PowerMock. Below is the thing I tried first.
public class GroupTestcase_T extends TestSuite {
static void run() {
scan();
junit.textui.TestRunner.run(g);
}
static void scan() {
// scan disk
for (MyTestCase t : tests) { addTest(t); }
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(ClassToStub.class)
public class MyTestCase extends TestCase {
public MyTestCase(TestInfo info) {...}
#Override
protected void setUp() throws Exception {
PowerMockito.mockStatic(ClassToStub.class);
when(ClassToStub.methodToStub())
.thenReturn(new FakeProxy());
}
#Test
public void test() throws Exception {
// Test!
}
}
Above code seems not working:
Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
2. inside when() you don't call method on mock but on some other object.
3. the parent of the mocked class is not public.
It is a limitation of the mock engine.
I traced the code and found that PowerMockRunner are not called at all.
Also I tried manually force Junit to run it with PowerMockRunner:
Result result = junit.run(new PowerMockRunner(MyTestCase.class));
PowerMockRunner has only one constructor that takes the test class as parameter. My test cases are different each time but all share the same class.
Any idea how to use PowerMock if TestCase are dynamically created?
I was using Junit 4 / PowerMock 1.5
You can generate your tests with the parameterized tests feature and apply the #PowerMockRule.
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
#RunWith(Parameterized.class)
#PrepareForTest(ClassToStub.class)
public class MyTestCase{
#Parameters
public static Collection<Object[]> scan() {
return Arrays.asList(new Object[][] {
{ new TestInfo() }, { new TestInfo() } });
}
#Rule
public PowerMockRule rule = new PowerMockRule();
public MyTestCase(TestInfo info) {
// ...
}
#Test
public void test() throws Exception {
PowerMockito.mockStatic(ClassToStub.class);
PowerMockito.when(ClassToStub.methodToStub()).thenReturn(new FakeProxy());
assertTrue(ClassToStub.methodToStub() instanceof FakeProxy);
}
}
Beware, in your example, you are mixing junit 3 (extends TestSuite, protected setUp) and junit 4 (#Test) test definitions.
Suppose I have a class like so:
public class StaticDude{
public static Object getGroove() {
// ... some complex logic which returns an object
};
}
How do I mock the static method call using easy mock? StaticDude.getGroove().
I am using easy mock 3.0
Not sure how to with pure EasyMock, but consider using the PowerMock extensions to EasyMock.
It has a lot of cool functions for doing just what you need -
https://github.com/jayway/powermock/wiki/MockStatic
Easymock is a testing framework for "for interfaces (and objects through the class extension)" so you can mock a class without an interface. Consider creating an interfaced object with an accessor for your static class and then mock that acessor instead.
EDIT: Btw, I wouldn't recommend doing static classes. It is better to have everything interfaced if you are doing TDD.
Just in Case PowerMock is unavailable for any reason:
You could move the static call to a method, override this method in the instantiation of the tested class in the test class, create a local interface in the test class and use its method in the overidden method:
private interface IMocker
{
boolean doSomething();
}
IMocker imocker = EasyMock.createMock(IMocker.class);
...
#Override
void doSomething()
{
imocker.doSomething();
}
...
EasyMock.expect(imocker.doSomething()).andReturn(true);
Generally speaking, it is not possible to mock a static method without using some sort of accessor, which seems to defeat the purpose of using a static method. It can be quite frustrating.
There is one tool that I know of called "TypeMock Isolator" which uses some sort of Satanic Magic to mock static methods, but that tool is quite expensive.
The problem is, I know of no way to override a static method. You can't declare it virtual. you can't include it in an interface.
Sorry to be a negative nelly.
Adding an exemple on how to implements static mock along regular mock of injected classes with EasyMock / PowerMock, since the linked exemple only shows static mock.
And with the PowerMockRunner the #Mock services are not wired on the #TestSubject service to test.
Let say we have a service we want to test, ServiceOne :
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class ServiceOne {
#Autowired
private ServiceTwo serviceTwo;
public String methodToTest() {
String returnServ2 = serviceTwo.methodToMock();
return ServiceUtils.addPlus(returnServ2);
}
}
Which calls another service that we will want to mock, ServiceTwo :
import org.springframework.stereotype.Service;
#Service
public class ServiceTwo {
public String methodToMock() {
return "ServiceTwoReturn";
}
}
And which calls a final class static method, ServiceUtils :
public final class ServiceUtils {
public static String addPlus(String pParam) {
return "+" + pParam;
}
}
When calling ServiceOne.methodToTest() we get "+ServiceTwoReturn" as a return.
Junit Test with EasyMock, mocking only the injected ServiceTwo Spring service :
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertEquals;
import org.easymock.EasyMockRunner;
import org.easymock.Mock;
import org.easymock.TestSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
#RunWith(EasyMockRunner.class)
public class ExempleTest {
#TestSubject
private ServiceOne serviceToTest = new ServiceOne();
#Mock
private ServiceTwo serviceMocked;
#Test
public void testMethodToTest() {
String mockedReturn = "return2";
expect(serviceMocked.methodToMock()).andReturn(mockedReturn);
replay(serviceMocked);
String result = serviceToTest.methodToTest();
verify(serviceMocked);
assertEquals("+" + mockedReturn, result);
}
}
Junit Test with EasyMock & PowerMock, mocking the injected ServiceTwo Spring service but also the final class and its Static method :
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertEquals;
import static org.powermock.api.easymock.PowerMock.createMock;
import static org.powermock.api.easymock.PowerMock.mockStatic;
import static org.powermock.reflect.Whitebox.setInternalState;
import org.easymock.Mock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(ServiceUtils.class)
public class ExempleTest {
private ServiceOne serviceToTest;
private ServiceTwo serviceMocked;
#Before
public void setUp() {
serviceToTest = new ServiceOne();
serviceMocked = createMock(ServiceTwo.class);
// This will wire the serviced mocked into the service to test
setInternalState(serviceToTest, serviceMocked);
mockStatic(ServiceUtils.class);
}
#Test
public void testMethodToTest() {
String mockedReturn = "return2";
String mockedStaticReturn = "returnStatic";
expect(serviceMocked.methodToMock()).andReturn(mockedReturn);
expect(ServiceUtils.addPlus(mockedReturn)).andReturn(mockedStaticReturn);
PowerMock.replayAll();
String result = serviceToTest.methodToTest();
PowerMock.verifyAll();
assertEquals(mockedStaticReturn, result);
}
}