Cant mock static functions with powermock-easymock-testng (non-maven project) - function

To tell you first, i have tried and tried it again and now i need some help
Heres my code
package staticPkg;
public class Static {
public static final String staticMethod() {
System.out.println("Static method called");
return "Static called";
}
}
package staticPkg;
public class TargetClass {
Static staticClass;
public String callHere() {
return Static.staticMethod();
}
}
package staticPkg;
import org.easymock.EasyMock;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.testng.IObjectFactory;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.ObjectFactory;
import org.testng.annotations.Test;
#PrepareForTest({Static.class})
public class TestClass {
Static staticClass = null;
#ObjectFactory
public IObjectFactory getObjectFactory() {
System.out.println("got object factory");
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
#BeforeMethod
public void setup() {
System.out.println("print me");
PowerMock.mockStatic(Static.class);
staticClass = PowerMock.createMock(Static.class);
}
#Test
public void testMe() {
EasyMock.expect(Static.staticMethod()).andReturn("Mock called").anyTimes();
PowerMock.replay(Static.class,staticClass);
TargetClass tc = new TargetClass();
String output = tc.callHere();
PowerMock.verify(Static.class,staticClass);
System.out.println(output);
}
}
And heres the log
[Parser] Running:
C:\MockWorkspace\Mock\temp-testng-customsuite.xml
got object factory
print me
Static method called
FAILED: testMe
java.lang.IllegalStateException: no last call on a mock available
at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:521)
at org.easymock.EasyMock.expect(EasyMock.java:499)
at staticPkg.TestClass.testMe(TestClass.java:46)
... Removed 22 stack frames
===============================================
staticPkg.TestClass
Tests run: 1, Failures: 1, Skips: 0
===============================================
===============================================
Mock
Total tests run: 1, Failures: 1, Skips: 0
===============================================
Help please, i have tried a variety of solutions, can't get it done.
Please can anyone try this code and correct it for success?
I get error in EasyMock.expect ...............
Got a work around at http://blogs.bytecode.com.au/glen/2006/10/12/doing-bytecode-kungfu-with-javassist.html
And it works
But wait..........I am stuck again
My testcase works fine when runs alone, but when run with Ant, it gives problem. Might be other test cases of different files are interfering.
I got the same error, when my individual test case was using #PrepareTest & easymock/powermock
[testng] ====================STATIC CALLED===========================
[testng] javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClass
Loader): attempted duplicate class definition for name: "com/symantec/mobius/aggregator/submission/SubmissionFactory"
[testng] at javassist.ClassPool.toClass(ClassPool.java:1085)
[testng] at javassist.ClassPool.toClass(ClassPool.java:1028)
[testng] at javassist.ClassPool.toClass(ClassPool.java:986)
[testng] at javassist.CtClass.toClass(CtClass.java:1110)

Try extending from PowerMockTestCase. The TestNG support will also be updated in next version of PowerMock (1.4.9).

I faced this same issue, and struggled a lot. Finally, found the following solution:
Another alternative is to set the object-factory to org.powermock.modules.testng.PowerMockObjectFactory in the TestNG suite.xml. Here is a sample suite file:
<suite name="dgf" verbose="10" object-factory="org.powermock.modules.testng.PowerMockObjectFactory">
<test name="dgf">
<classes>
<class name="com.example.ClientTest"/>
</classes>
</test>
</suite>
Of course, you can also extend your test case from PowerMockTestCase as told by Johan.

Mock all the static methods in static class before proceeding to mock the static method. Try with this:
#Test
public void testMe() {
PowerMock.mockStatic(Static.class);
EasyMock.expect(Static.staticMethod()).andReturn("Mock called").anyTimes();
PowerMock.replay(Static.class,staticClass);
TargetClass tc = new TargetClass();
String output = tc.callHere();
PowerMock.verify(Static.class,staticClass);
System.out.println(output);
}

Related

Junit 5 : AssertionFailedError: expected: <true> but was: <false>

I'm trying to write a unit test case for the below function in the service class
#Service
public class currencyHandler {
public boolean isNoDecimal(String currency) {
return "JPY".equalsIgnoreCase(currency) || "KRW".equalsIgnoreCase(currency);
}
}
Below is the unit case:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.svc.it.handlers;
#ExtendWith(SpringExtension.class)
public class CurrencyTests {
#Mock
CurrencyHandler currencyHandlerTest;
#Test
public void isNoCurrency() throws Exception {
assertTrue(currencyHandlerTest.isNoCurrency("ABC"));
assertTrue(currencyHandlerTest.isNoCurrency("XYZ"));
assertFalse(currencyHandlerTest.isNoCurrency("BOGUS"));
assertFalse(currencyHandlerTest.isNoCurrency(""));
assertFalse(currencyHandlerTest.isNoCurrency(null));
}
}
Below is the error when I run above unit test case:
org.opentest4j.AssertionFailedError: expected: <true> but was: <false>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:40)
at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:35)
at org.junit.jupiter.api.Assertions.assertTrue(Assertions.java:162)
I guess I'm doing something wrong with #Mock object.
Appreciate your help. Thanks in advance!
To write a unit test for the CurrencyHandler class, you must test against an instance of that class. You must not test against an instance of a mock of that class.
The following shows how to write such a unit test.
package example;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class CurrencyHandlerTests {
private CurrencyHandler currencyHandler = new CurrencyHandler();
#Test
void isNoDecimal() {
assertTrue(currencyHandler.isNoDecimal("JPY"));
assertTrue(currencyHandler.isNoDecimal("KRW"));
assertFalse(currencyHandler.isNoDecimal("BOGUS"));
assertFalse(currencyHandler.isNoDecimal(""));
assertFalse(currencyHandler.isNoDecimal(null));
}
}
To better understand the concepts here, I recommend that you read some articles or books on unit testing, mocks, and the SUT (subject under test).
In addition, you do not need to register the SpringExtension if you are writing a pure unit test like the one above, since a pure unit test does not need to interact with components in a Spring ApplicationContext.

How to access protected method of Java jar file's class

I am using a Java command-line application (which is open-source) as a jar file for my jrubyonrails project. The main application is like following
public class Decoder extends Annotator {
public Decoder() {
super();
}
public static void main(String[] args) {
... // Do something that I don't want
myDesiredMethod();
... // And some other thing
}
...
}
There are many steps which I want to skip, I only want myDesiredMethod function. And it is a protected method from the parent Annotator class.
public class Annotator extends Helper {
...
protected SomeClass myDesiredMethod(boolean reMap) throws Exception { ... }
...
}
Annotator class does not have any public constructor so that I cannot:
ann = Annotator.new
It raises this error: TypeError: no public constructors for Annotator.
Then I try to implement another class which inherits Annotator in order to access myDesiredMethod. This is the jruby code I have tried so far
require 'java'
require 'decoder.jar'
java_import java.util.ArrayList
java_import java.lang.StringBuilder
module MyModule
class RuDecoder < Annotator
include_package 'com.decoder'
def self.my_method
myDesiredMethod
end
end
It returns the error: NoMethodError: undefined method 'myDesiredMethod' for MyModule::RuDecoder:Class. Seems jruby does not look for the method of the parent class.
Is there any solution in my case, I don't want to rebuild the java library to jar and manually put it into my program every time it has an update.
Turns out that I made thing over-complicated. I can call the default constructor of Annotator as following:
constructors = Annotator.java_class.declared_constructors.first
constructors.accessible = true
annotator = constructors.new_instance.to_java
And use simple call myDesiredMethod: annotator.myDesiredMethod

CDI injection and JUnit

I am trying to add JUnit tests to a Tomee web-application that uses CDI and JPA. Leaving out the different hurdles of the last two weeks (including very intensive research on stackoverflow as well as other sources), my problem appears to be quite concrete:
Running the unit test gives this error message:
org.apache.openejb.Injector$NoInjectionMetaDataException:
org.demo.service.GenericServiceTest : Annotate the class with #javax.annotation.ManagedBean so it can be discovered in the application scanning process
at org.apache.openejb.Injector.inject(Injector.java:54)
at org.apache.openejb.OpenEjbContainer$GlobalContext.bind(OpenEjbContainer.java:656)
...
This I don't understand, for I have annotated the class just as required. Any idea what I can do to resolve this?
(Or does the error refer to the injected class - GenericService? I cannot annotate this #ManagedBean, for it is already #Stateless).
Here are some details of my project:
gradle dependencies:
dependencies {
compile 'org.apache.commons:commons-lang3:3.3.2'
compile "com.googlecode.json-simple:json-simple:1.1.1"
compile group: 'com.fasterxml.jackson.core', name: 'jackson-annotations', version: '2.8.6'
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.8.6'
compile 'log4j:log4j:1.2.16'
testCompile "org.apache.openejb:tomee-embedded:1.7.3"
compile "javax:javaee-api:7.0"
compile 'mysql:mysql-connector-java:5.1.16'
}
(I have put the testCompile inbetween, because there is a ticket stating the importance of the order: EJB testing with TomEE embedded EJBContainer api: java.lang.ClassFormatError exception)
My Test class is this:
package org.demo.service;
import java.io.File;
import java.util.Properties;
import javax.annotation.ManagedBean;
import javax.ejb.embeddable.EJBContainer;
import javax.inject.Inject;
import javax.naming.NamingException;
import org.apache.openejb.OpenEjbContainer;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
#ManagedBean
public class GenericServiceTest {
private static EJBContainer ejbContainer;
#Inject
private GenericService service;
#Test
public void test() throws NamingException {
System.out.println("service: " + service);
}
#BeforeClass
public static void start() {
Properties p = new Properties();
try {
p.put(EJBContainer.MODULES, new File("bin"));
} catch (Exception e1) {
e1.printStackTrace();
}
p.put(OpenEjbContainer.Provider.OPENEJB_ADDITIONNAL_CALLERS_KEY, GenericService.class.getName());
ejbContainer = javax.ejb.embeddable.EJBContainer.createEJBContainer(p);
}
#Before
public void inject() throws NamingException {
ejbContainer.getContext().bind("inject", this);
}
#AfterClass
public static void shutdownContainer() {
if (ejbContainer != null) {
ejbContainer.close();
}
}
}
Maybe I'm running totally in the wrong direction here - Please let me know if I should choose a different approach - All I want is to add unit tests to my web application (preferably without introducing Weld/JBoss or other implementations as alternatives to the implementations I already use in the application itself).
Thank you very much in advance!
I would recommand you to read http://tomee.apache.org/developer/testing/index.html , there are some examples
Regarding your test it uses openejb embedded and not tomee embedded and deploys bin/ as an application. the hack bind("inject") only works with classpath deployment (no module).

Error in Parameterised test cases in Junit

I am trying to write a parameterized test case in JUnit. My code looks like this:
#RunWith(Parameterized.class)
#PrepareForTest({AR9DirectDebitFileWriterCustomization.class})
public class AR9DirectDebitFileWriterCustomizationTest2 extends AR3BasicUnitTest {
private DirectDebitExtractDetRec mockObj;
private ARApplicationContext mockAppCon;
private AR9DirectDebitFileWriterCustomization spyObj = null;
AccountDBViewData mockdbData;
AccountDBView mockdbView;
SearchInvoicesDBViewData[] mocksearchInvdbviewdatarr = new SearchInvoicesDBViewData[1];
#Before
public void setUp() throws Exception {
AR9DirectDebitFileWriterCustomization ar9Obj = new AR9DirectDebitFileWriterCustomization(mockdbView, mocksearchInvdbviewdatarr, mockdbData);
spyObj = PowerMockito.spy(ar9Obj);
}
public AR9DirectDebitFileWriterCustomizationTest2(DirectDebitExtractDetRec mockObj_from_collection, ARApplicationContext mockAppCon_from_collection) {
this.mockObj = mockObj_from_collection;
this.mockAppCon = mockAppCon_from_collection;
}
#Parameterized.Parameters
public static Collection<Object[]> getparameters() throws ACMException{
return Arrays.asList(new Object[][]{
{mock(DirectDebitExtractDetRec.class),mock(ARApplicationContext.class)}
});
}
#Test
#Parameters
public final void testAddFileRecordCustObjectARApplicationContext( ) throws Exception {
.....SOME CODE
}
Whenever I right click on the testAddFileRecordCustObjectARApplicationContext function and run it as Junit test I get an initialization error :
java.lang.Exception: No tests found matching Method
testAddFileRecordCustObjectARApplicationContext(amdocs.ar.customizationexits.handlers.helpers.AR9DirectDebitFileWriterCustomizationTest2)
from org.junit.internal.requests.ClassRequest#3fa50b at
org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:37)
at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.(JUnit4TestReference.java:33)
at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestMethodReference.(JUnit4TestMethodReference.java:25)
at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:54)
at
org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:38)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:452)
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)
After looking for several hours on internet about this issue I could not find anything meaningful. In this scenario I am using spy and powerMocktio Functionality as well.I am not sure what is the root of this error .
And interesting thing is when I run it without using Parameterised test ,it works perfectly fine.
I had very similar error:
No tests found matching data with any parameter from...
According to my observations, it is caused by another strange error:
Unable to mock class ... due to a missing dependency
Only the first I see when I run the test, and the second, when I debug it. According to https://stackoverflow.com/a/23788935/715269,
https://stackoverflow.com/a/25659518/715269, it is the bug connected to classpath reading. The problem disappears, when we upgrade JMockit to higher versions.

junit custom ParameterSupplier

all of the samples i've seen online with regard to custom parametersuppliers have something like:
List<PotentialAssignment> list = new ArrayList<PotentialAssignment>();
list.add(PotentialAssignment.forValue("teams", "giants"));
list.add(PotentialAssignment.forValue("teams", "jets"));
list.add(PotentialAssignment.forValue("teams", "niners"));
return list;
now, the question i have is: what does the first argument to PotentialAssignment.forValue(arg1, arg2) do? Nothing i've seen online has explained the significance of it.
thanks
The first parameter of PotentialAssignment.forValue is the "name" of the value. It is not used, if your #Theory method passes, but if it fails, it is used to assemble the error message. Here is an example:
#RunWith(Theories.class)
public class CustomParameterSupplierTest {
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
#ParametersSuppliedBy(FooSupplier.class)
public #interface Foo {}
public static class FooSupplier extends ParameterSupplier {
#Override
public List<PotentialAssignment> getValueSources(ParameterSignature sig) {
return Arrays.asList(
PotentialAssignment.forValue("one", 1),
PotentialAssignment.forValue("two", 2)
);
}
}
#Theory
public void test(#Foo int foo) {
assertThat(foo, is(1));
}
}
If this test is executed with Junit 4.11 you will get the following error:
org.junit.experimental.theories.internal.ParameterizedAssertionError: test(two)
By the way, in the upcoming release JUnit 4.12 the error reporting is further improved and you will get the following error:
org.junit.experimental.theories.internal.ParameterizedAssertionError: test("2" <from two>)