I am writing a JUnit test case for a method which internally invokes another method through interface. I am using Mockito to mock the interface but for some reason it gives me NPE. I debugged through but wasn't able to get any clue to fix it. getAllVendors() method throws exception which comes through an Interface.
MUT
public void prepare() throws AccountServiceException, ManagerException {
vendors = getVendorManager().getAllVendors();
microsites = new ArrayList<VendorMicrositeTO>();
microsites.add( new VendorMicrositeTO( "http://www.docusign.com", "docuSign" ) );
clientUser = createClientUserObject();
}
JUnit
#Test
public void testPrepare() throws Exception {
AccountAction accountAction = new AccountAction();
Map<String, Object> actionMap = new HashMap<>();
actionMap.put("application", "ESignatureIntegrationAction");
ActionContext.setContext(new ActionContext(actionMap));
String beanName = Constants.VENDOR_MANAGER_SPRING_BEAN;
PowerMockito.mockStatic(AppContext.class);
PowerMockito.when(AppContext.containsBean( beanName )).thenReturn( true );
IVendorDto iVendorDto = new VendorDto();
iVendorDto.setActive(true);
iVendorDto.setCreatedBy("9/15/2016");
iVendorDto.setName("CorpESignClientUser");
iVendorDto.setCreatedBy("SYSTEM");
List<IVendorDto> vendorList = new ArrayList<>();
vendorList.add(iVendorDto);
IVendorManager iManager = Mockito.mock((IVendorManager.class));
Mockito.when(iManager.getAllVendors()).thenReturn(vendorList);
accountAction.setVendors(vendorList);
accountAction.prepare();
}
Stack trace
java.lang.NullPointerException
at com.mercuryinsurance.esignature.ui.webapp.action.AccountAction.prepare(AccountAction.java:65)
at test.com.mercuryinsurance.esignature.ui.webapp.action.TestAccountAction.testPrepare(TestAccountAction.java:58)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Thanks, in advance
Seems you forgot to add a line in your test like:
accountAction.setVendorManager(iManager);
So yeah, I have been tackling a very similar issue.
This usecase is a logical outcome of the application of the SOLID principles within an IoT based application. If you decouple the layers of your application using interfaces and are testing an innner layer you are bound to come across testing an interface whose implementations have more interface dependencies.
You can achieve this goal using two testing angles combined
Use the Parameterized JUnit runner to launch the one set of unit tests for all of the implementations.
Then internally during each run initialize the mocked dependencies using Mockito
For more information on Parameterized testing (that's where i originally found it) be sure to visit this post. The manual initialization of mockito was something i found here.
All and all the resulting code looks like this:
#RunWith(Parameterized.class)
public class YourInterfaceTest {
#Mock
private ImplementationDependency sneakyBreakyNpeAvoided;
#InjectMocks
private YourInterfaceToTest iface;
// constructor is used by the Parameterized runner to provide impelementations
public YourInterfaceTest (YourInterfaceToTest ifaceToTest) {
this.iface = ifaceToTest;
}
// this method is called always before running tests so a good time to inject anything
#Before
public void init() {
MockitoAnnotations.initMocks(this);
Mockito.when(sneakyBreakyNpeAvoided.returnTrue()).thenReturn(true);
}
#Test(expected = IllegalArgumentException.class)
public void doSomething_nullParameter_throwsIllegalArgumentException() {
Assert.fail(); // tests here :)
}
#Parameterized.Parameters
public static Collection<YourInterfaceToTest > provideImplementations() {
// change to Arrays.asList when multiple implementations are available
return Collections.singletonList(new YourInterfaceImpl());
}
}
Hope I understood the OP's issue well.
Related
In a simple test class like the one below:
#SpringBootTest
#Slf4j
#ActiveProfiles("test")
public class LocalizerTest {
#Autowired
AddressInfoLocalizer addressInfoLocalizer;
#Test
public void localizeIp() {
String ip = "8.8.8.8";
Optional<CityResponse> response = addressInfoLocalizer.localize(ip);
response.ifPresent(cityResponse -> log.info("{}", cityResponse));
}
}
With the AddressInfoLocalizer (sorry for the strange name but I had to make it up) being basically like this:
#Slf4j
#Component
public class AddressInfoLocalizer {
#Value("${geolocalization.dbpath}")
private String databasePath;
private DatabaseReader database;
#PostConstruct
public void initialize() {
log.info("GeoIP2 database path:{}", databasePath);
File database = new File(databasePath);
try {
this.database = new DatabaseReader.Builder(database).build();
} catch (IOException ioe) {
this.database = null;
log.warn("Problems encountered while initializing IP localization database, skipping resolutions");
}
}
public Optional<CityResponse> localize(String ipAddressString) {
if (isNull(database)) {
log.warn("Attempted to resolve an IP location with database problems, skipping.");
return Optional.empty();
}
try {
InetAddress ipAddress = InetAddress.getByName(ipAddressString);
return ofNullable(database.city(ipAddress));
} catch (UnknownHostException uhe) {
log.error("Unknown host {}, {}", ipAddressString, uhe.getCause());
return Optional.empty();
} catch (IOException ioe) {
log.error("IO error while opening database, {}", ioe.getCause().toString());
return Optional.empty();
} catch (GeoIp2Exception gip2e) {
log.error("GeoIP error, {}", gip2e.getCause().toString());
return Optional.empty();
}
}
}
I keep getting a NullPointerException when calling (in the test) addressInfoLocalizer.localize(ip);,
java.lang.NullPointerException
at com.bok.parent.LocalizerTest.localizeIp(LocalizerTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
while debugging I can actually see that the addressInfoLocalizer object is null.
I've created other classes the same way, but only this one seems to have that problem, what could be wrong?
What I found out is that not always the #SpringBootTest is enough, in some classes/cases (to be honest I don't have a 100% clear idea so I'm not gonna say stupidities) it is needed that you manually choose the test-runner, like below:
#SpringBootTest
#RunWith(SpringRunner.class)
public class FooTest {
...
}
Keep in mind that if you decide to instantiate a dependency by yourself then Spring won't be able to inject all the needed classes, and then you'd need to change the runner into something like #RunWith(MockitoJUnitRunner.class)
(credits to JUNIT Autowired instance is always null)
A better approach is to use spring's underlying mock beans.
#SpringBootTest(classes= AddressInfoLocalizer.class)
this is actually the new recommended way.
Two things here:
If you're testing, the ideal way is to mock instead of autowire(there can be exceptions)
You should use #ExtendWith(MockitoExtension.class) or #RunWith(MockitoJUnitRunner.class) so that your components will be loaded in spring context. However ExtendWith is preferred way to initialize beans/components. Because the later(RunWith) loads the entire spring context which might take more time
So, your code should look something like:
#Slf4j
#ActiveProfiles("test")
#ExtendWith(MockitoExtension.class)
public class LocalizerTest {
#Mock
AddressInfoLocalizer addressInfoLocalizer;
#Test
public void localizeIp() {
String ip = "8.8.8.8";
//Mock here.
Optional<CityResponse> response = addressInfoLocalizer.localize(ip);
response.ifPresent(cityResponse -> log.info("{}", cityResponse));
}
}
Reference/Read more:
https://www.baeldung.com/mockito-junit-5-extension
https://stackoverflow.com/questions/55276555/when-to-use-runwith-and-when-extendwith
https://www.javadoc.io/static/org.mockito/mockito-junit-jupiter/3.10.0/org/mockito/junit/jupiter/MockitoExtension.html
I am trying to mock enum using powerMock but got Field 'fTestClass' was not found in class error when i ran test. I found that the issue is with Junit 4.12 and powermock-module-junit4 1.5.6. so I changed to 1.6.1 now I am getting below error ...
java.lang.ExceptionInInitializerError
at sun.reflect.GeneratedSerializationConstructorAccessor9.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
at org.mockito.internal.creation.jmock.ClassImposterizer.createProxy(ClassImposterizer.java:142)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:61)
at org.powermock.api.mockito.internal.mockcreation.MockCreator.createMethodInvocationControl(MockCreator.java:109)
at org.powermock.api.mockito.internal.mockcreation.MockCreator.mock(MockCreator.java:57)
at org.powermock.api.mockito.PowerMockito.mockStatic(PowerMockito.java:70)
at OrderEventProcessorTest.setUp(OrderEventProcessorTest.java:47)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.internal.runners.MethodRoadie.runBefores(MethodRoadie.java:133)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:122)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:106)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.NullPointerException
Basically I am trying to mock enum to check the functionality of insert, update, delete operations to cassandra db. the enum gives setups the cassadra db connection. I want to mock it so I don't need to connect to the DB to test my crud functionality. Please let me know if still is there any versioning issues with Junit 4.12 and powermock 1.6.1 . I am using mockito-core 1.10.19 and maven-surefire-plugin 2.19.1
EDITED
ENUM for DB connection
public enum CassProvider {
INSTANCE;
private Map<String,ThreadLocal<PreparedStatement>> psMap;
private String[] hostnames;
private String username;
private String password;
private String keyspace;
private Cluster cluster;
private Session session;
private CassProvider() {
init();
psMap = createPreparedStatements();
}
private void init() {
//get host, port, user , pasword from properties file
cluster = Cluster.builder().addContactPoints(hostnames).withPort(port).withCredentials(username, password).build();
session = cluster.connect(keyspace);
}
private static Map<String,ThreadLocal<PreparedStatement>> createPreparedStatements() {
//code goes for mapping preparedStatements
return psMap;
}
public PreparedStatement getPreparedStatement(String id) {
//logic for preparedStatement
return preparedStatement;
}
public Session getSession() {
return session;
}
}
Code I would like to test for different conditions it executes different prepared statements
if (eventMappingType != null && processEvent) {
.......
BatchStatement batchStatement = new BatchStatement();
PreparedStatement psFieldInsert = CassProvider.INSTANCE.getPreparedStatement("INSERT_ORDERS_FV");
if (eventMappingType.getSimpleFields() != null) {
for (FieldType fieldType : eventMappingType.getSimpleFields().getField()) {
Object value = MVEL.executeExpression(fieldType.getSerializedExpr(), context);
batchStatement.add(psFieldInsert.bind(keyFields.get("orderNumber"),dateStringToDate(eventDateTime), fieldType.getValue(), value != null ? value.toString() : value));
}
}
if (eventType.compareToIgnoreCase("OrderPlaced") == 0) {
//Update the lookup table for given name 2 orders.
if (name != null && name.compareToIgnoreCase("")!=0) {
batchStatement.add(CassProvider.INSTANCE.getPreparedStatement("INSERT_ORDERS_BY_NAME").bind(name, dateStringToDate(eventDateTime), orderNumber));
}
//Update the lookup table for accIds 2 orders; not sure if we need this for now
if (accIds != null && accIds.compareToIgnoreCase("")!=0) {
batchStatement.add(CassProvider.INSTANCE.getPreparedStatement("INSERT_ORDERS_BY_ACCIDS").bind(accIds, dateStringToDate(eventDateTime), orderNumber));
}
if (SAPOrderNumber != null) {
batchStatement.add(CassProvider.INSTANCE.getPreparedStatement("INSERT_SAP_ORDER").bind(SAPOrderNumber, orderNumber));
}
}
CassProvider.INSTANCE.getSession().execute(batchStatement);
}
Not sure how your Cluster.builder() method works but I suggest you make that you configurable, i.e. to open it up for your test class to inject a mocked builder that in the end returns a mocked Cluster that in turn returns a mocked Session...
I have question that similar to my previous question where I have the following class:
public class FileClass {
public void funcB() throws ClassNotFoundException {
throw new ClassNotFoundException();
}
}
I would like to test whether ClassNotFoundException will be thrown when funcB() is called. Thus I have this test code:
public class TestFileClass {
#Test(expected=ClassNotFoundException.class)
public void testFuncB() throws ClassNotFoundException {
FileClass fc = Mockito.spy(new FileClass());
Mockito.doThrow(new ClassNotFoundException())
.when(fc).funcB();
}
}
But the test were failed due to following error:
java.lang.AssertionError: Expected exception: java.lang.ClassNotFoundException
at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:35)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Any clue how could I test ClassNotFoundException in funcB()?
If you're testing a method invocation on an instance of type FileClass, don't mock the instance. Just create an actual instance and call the method.
#Test(expected = ClassNotFoundException.class)
public void testFuncB() throws ClassNotFoundException {
FileClass fc = new FileClass();
fc.funcB();
}
Mocking is meant for things that you know ([would]) work but don't want to setup.
As #dzezzz states in the comments, a ClassNotFoundException (is that really the exception you want to test?) could be thrown in the FileClass constructor. If that is not something that should happen and that you want to test, you can set up the following test so that it is only expected from the method invocation
#Rule
public ExpectedException exception = ExpectedException.none();
#Test()
public void testFuncB() throws ClassNotFoundException {
FileClass fc = new FileClass();
exception.expect(ClassNotFoundException.class);
fc.funcB();
}
The test will pass only if a ClassNotFoundException is thrown after the ExpectedException#expect() call.
If you test FileClass then don't mock it. You should mock the classes which are used by FileClass.
If you don't want that the exception will come out from test method.
There is a solution:
#Test(expected = ClassNotFoundException.class)
public void testFuncB(){
try{
FileClass fc = new FileClass();
fc.funcB();
fail();
}catch(ClassNotFoundException ex){
}
}
In this solution you catch the exception if it is thrown but your test fails when it isn't.
Problem: The instrumentation class in PowerMock isn't being initialized. I'm loading the library through the #Rule annotation. I've got the VM argument in place:
-javaagent:project_path/libs/powermock-module-javaagent-1.5.jar
When I walk through with the debugger, PowerMockAgent#premain gets called and the instrumentation object gets set, but when it's called during the test setup, the instrumentation object is null, throwing the error below.
Why is the instrumentation variable not keeping it's value between when PowerMockAgent#premain is called and when PowerMockClassRedefiner.redefine calls it?
Instrumentation gets set correctly here on load:
private static void initialize(String agentArgs, Instrumentation inst) throws IOException {
instrumentation = inst;
inst.addTransformer(new DefinalizingClassTransformer(), false);
inst.addTransformer(classTransformer, true);
}
But when called again from #PrepareForTest({ Logger.class }), is null
public class PowerMockClassRedefiner {
public static void redefine(Class<?> cls) {
if(cls == null) {
throw new IllegalArgumentException("Class to redefine cannot be null");
}
PowerMockAgent.getClasstransformer().setClassesToTransform(Arrays.asList(cls.getName()));
try {
PowerMockAgent.instrumentation().retransformClasses(cls);
} catch(Exception e){
throw new RuntimeException("Failed to redefine class "+cls.getName(), e);
}
}
Resulting in error:
java.lang.RuntimeException: Failed to redefine class com.testapp.Logger
at org.powermock.modules.agent.PowerMockClassRedefiner.redefine(PowerMockClassRedefiner.java:33)
at org.powermock.modules.agent.PowerMockClassRedefiner.redefine(PowerMockClassRedefiner.java:42)
at com.testapp.testFramework.PowerMockRuleAgentSetup.redefine(PowerMockRuleAgentSetup.java:29)
at com.testapp.testFramework.PowerMockRuleAgentSetup.initialize(PowerMockRuleAgentSetup.java:19)
at com.testapp.testFramework.PowerMockOverriderRule.apply(PowerMockOverriderRule.java:19)
at org.junit.runners.BlockJUnit4ClassRunner.withMethodRules(BlockJUnit4ClassRunner.java:341)
at org.junit.runners.BlockJUnit4ClassRunner.withRules(BlockJUnit4ClassRunner.java:330)
at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:248)
at com.xtremelabs.robolectric.RobolectricTestRunner.methodBlock(RobolectricTestRunner.java:287)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.NullPointerException
at org.powermock.modules.agent.PowerMockClassRedefiner.redefine(PowerMockClassRedefiner.java:31)
... 22 more
Here's my test setup:
#RunWith(RobolectricTestRunner.class)
#PrepareForTest({ Logger.class }) // THIS IS WHERE THE ERROR GETS THROWN
public class LoggerTest {
#Rule public PowerMockOverriderRule rule = new PowerMockOverriderRule();
public LoggerConfig config;
#Before
public void setUp() {
config = mock(LoggerConfig.class);
}
UPDATE:
Removing the #RunWith(RobolectricTestRunner.class) fixes the problem, but isn't an option for my project. (It's an Android project).
I'm sorry to ask but why would you even want to mock a Logger class? If you want to ensure that the output is logged to the console you can wrap a logger in an abstraction that you can mock.
class LogWraper {
void someMethod() {
logger.log()
}
}
and then you can create a mock of your FooWraper. No need to use Powermock at all...
I have the following code
public class A{
public void createFile() {
File tempXmlFile = null;
String extension = ".xml";
String name = "someName";
try {
tempXmlFile = File.createTempFile(name, extension);
if (tempXmlFile.exists()) {
tempXmlFile.delete();
}
} catch (IOException e) {
System.out.println(e.getStackTrace());
}
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.class)
public class testA extends TestCase{
private A classUnderTest;
#Override
#Before
public void setUp() {
classUnderTest = PowerMock.createMock(A.class); //the class is more complex in my case and I have to mock it
}
public void testCreateFile() throws IOException{
String extension = ".xml";
String name = "someName";
PowerMock.mockStatic(File.class);
File tempFileMock = PowerMock.createMock(File.class);
expect(File.createTempFile(name, extension)).andReturn(tempFileMock);
expect(tempFileMock.exists()).andReturn(true);
expect(tempFileMock.delete()).andReturn(true);
replay(File.class, tempFileMock, classUnderTest);
classUnderTest.createFile();
verify(File.class, tempFileMock, classUnderTest);
}
}
In the test class as I said the class under test must be mocked(I can't create a new object).
When I run the test I get:
java.lang.IllegalStateException: no last call on a mock available
at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:174)
at org.easymock.EasyMock.expect(EasyMock.java:156)
at myPackage.testA.testCreateFile(testA.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59)
at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:163)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:120)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:113)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:111)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:87)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:44)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
I read the documentation here http://code.google.com/p/powermock/wiki/MockSystem but the test stil wont't work. Am I missing something?
Edit: I tested the previous code with a real A object (and removed it from replay)
classUnderTest = new A();
but I still get the same exception.
Try adding File.class to #PrepareForTest.
try the org.powermock.reflect.internal.WhiteboxImpl.newInstance() method to create the object of the class and then call method directly.
1) this will suppress the constructor of the class
2) if your class contains static block then use suppressStaticInitilaizationFor to suppress that.
regards
Anil Sharma
Add File.class to #PrepareForTest and check the imports of replay and verify. They should be from PowerMock.
I think you need to suppress constructor
Check this
http://code.google.com/p/powermock/wiki/SuppressUnwantedBehavior