Getting PowerMockito to mock a static method on an Interface? - java

I have a library I am trying to mock for testing... There is a Java 8 interface with a static method implementation like this:
public interface Router {
public static Router router(Object param) {
return new RouterImpl(param);
}
}
And I am trying to mock that returned value:
PowerMockito.mockStatic(Router.class);
PowerMockito.doReturn(mockRouter).when(Router.router(any()));
But when I run the tests through a debugger, the mock instance is not returned.
I've tried a number of different permutations of the static mocking, but I cannot get the static method to return my mock value. Any thoughts?

You are doing it right, but we will have to wait when mocking static interface method is implemented/fixed in PowerMock. Watch this pull request:
https://github.com/jayway/powermock/issues/510
Note: Good news is that issue in Javassist is already fixed:
https://github.com/jboss-javassist/javassist/pull/11

Why not wrap it in an abstraction that you can mock?
class RouterFactory {
Router createRouter(Object param) {
return Router.router(param);
}
}
And use it in your class
class YourClass {
private final RouterFactory routerFactory;
YourClass(RouterFactory routerFactory) {
this.routerFactory = routerFactory;
}
void doSth() {
// do sth
}
}
Then you can mock the RouterFactory without any problems and you don't have to use Powermock.

Related

Using Mockito spy in one class to Call static method from another class

Trying to use Mockito's spy function for my JUnit test. I originally had a Class:
public class App1 {
public String method1() {
sayHello();
}
public sayHello() {
Systems.out.println("Hello");
}
}
Everything in my test class was working correctly with mockito spy on above class:
#Test(expected = IOException.class)
public void testMethod1Failure(){
App1 a1 = spy(App1);
doThrow(IOException.class).when(a1).sayHello();
a1.method1();
}
But after that i had to switch things around and take sayHello() method into another class to be used as static method:
public class App1 {
public String method1() {
App2.sayHello();
}
}
public class App2 {
public static void sayHello() {
Systems.out.println("Hello");
}
}
After this change, my original JUnit testcase is broken and i am unsure how i can use Mockito spy to start App1 that calls the external App2 static method... does anyone know how i can do it? Thanks in advance
Mockito does not support mocking static code. Here are some ways to handle it:
Use PowerMockito or similar framework as suggested here: Mocking static methods with Mockito.
Refactor your code converting static method back to an instance method. As you've found static methods are not easy to Unit test.
If it's inexpensive to execute actual static method in question then just call it.

Mockito Verification of send mail method in another static class

public class SomeclassTobeTested {
public int doSomethingAndSendMail(){
//... doing something
SomeStaticClass.sendEmail(args);
}
}
Public static SomeStaticClass implements Runnable{
public void run(){
sendMail();
}
public static void senMail(args){
//starts the thread
}
}
public class TestSomeClassToBeTested{
}
So now I have to verify whether sendEmail was called from doSomethingAndSendMail()? Which class should I mock? And not actually send the email.
You cannot verify static methods with Mockito . You have to use Powermockito to do that.
However, I suggest you refactor your code so the sendEmail method is a member of an object, perhaps of a dependency. This dependency can then be mocked and the sendEmail method can be stubbed and verified with Mockito. Having to use Powermockito usually means bad practice.
More information can be found in these answers: Mocking static methods with Mockito and Why is using static helper methods in Java bad?

How to mock local variable obtained from another method of tested class?

I have following class
class MyClass{
public void m(InputStream is){
...
Parser eParser = getExcelFileParser();
eParser.parse(is);
...
eParser.foo();
eParser.bar();
}
public ExcelFileParser getExcelFileParser(){
...
}
}
How to write unit test for method m at this situation? I want to mock eParser object only.
Is it possible?
I use Mockito and PowerMockito
You can do what you want in Mockito (no PowerMock needed) using a spy without changing your code at all.
In your unit test you need to do something like the following:
ExcelFileParser parser = mock(ExcelFileParser.class);
MyClass myClass = spy(new MyClass());
doReturn(parser).when(myClass).getExcelFileParser();
Can you pass AnotherObject as a parameter into the method m rather than calling getAnotherObject() in the method itself?
Preface: I use EasyMock not Mockito so this may be a bit off.
Can't you create an inner subclass of MyClass in your test that overrides getExcelFileParser and has it return a mock? Like this:
public class MyClassMock extends MyClass {
ExcelFileParser _mock;
public MyClassMock(ExcelFileParser mock) {
_mock = mock;
}
#Override
public ExcelFileParser getExcelFileParser() {
return _mock;
}
}
I haven't tested this so there could be issues with this, but the basic idea should be right.

How to mock static method in Java?

I have a class FileGenerator, and I'm writing a test for the generateFile() method that should do the following:
1) it should call the static method getBlockImpl(FileTypeEnum) on BlockAbstractFactory
2) it should populate variable blockList from the subclass method getBlocks()
3) it should call a static method createFile from a final helper class FileHelper passing a String parameter
4) it should call the run method of each BlockController in the blockList
So far, I have this empty method:
public class FileGenerator {
// private fields with Getters and Setters
public void generateBlocks() {
}
}
I am using JUnit, Mockito to mock objects and I've tried using PowerMockito to mock static and final classes (which Mockito doesn't do).
My problem is: my first test (calling method getBlockList() from BlockAbstractFactory) is passing, even though there is no implementation in generateBlocks(). I have implemented the static method in BlockAbstractFactory (returning null, so far), to avoid Eclipse syntax errors.
How can I test if the static method is called within fileGerator.generateBlocks()?
Here's my Test Class, so far:
#RunWith(PowerMockRunner.class)
public class testFileGenerator {
FileGenerator fileGenerator = new FileGenerator();
#Test
public void shouldCallGetBlockList() {
fileGenerator.setFileType(FileTypeEnum.SPED_FISCAL);
fileGenerator.generateBlocks();
PowerMockito.mockStatic(BlockAbstractFactory.class);
PowerMockito.verifyStatic();
BlockAbstractFactory.getBlockImpl(fileGenerator.getFileType());
}
}
I have no experience with PowerMock, but since you didn't get an answer yet I'm just been reading through the documentation to see if I can help you a bit on your way.
I found that you need to prepare PowerMock so that I knows which static methods it needs to prepare to be mocked. Like so:
#RunWith(PowerMockRunner.class)
#PrepareForTest(BlockAbstractFactory.class) // <<=== Like that
public class testFileGenerator {
// rest of you class
}
Here you can find more information.
Does that help?
Working example:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ClassStaticA.class, ClassStaticB.class})
public class ClassStaticMethodsTest {
#Test
public void testMockStaticMethod() {
PowerMock.mockStatic(ClassStaticA.class);
EasyMock.expect(ClassStaticA.getMessageStaticMethod()).andReturn("mocked message");
PowerMock.replay(ClassStaticA.class);
assertEquals("mocked message", ClassStaticA.getMessageStaticMethod());
}

Mocking a class object using Mockito and PowerMockito

Is it possible to mock a class object using Mockito and/or PowerMockito?
Something like:
Class<Runnable> mockRunnableClass = mock(Class<Runnable>.class);
An alternative to mocking Class might be to use a Factory instead. I know you are concerned about refactoring, but this could be done without changing the public API of the class. You haven't provided much code to understand the class you are trying to test, but here's an example of refactoring without changing the API. It's a trivial class, but it might give you an idea.
public class Instantiator {
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return runnableClass.newInstance();
}
}
Of course, the easiest thing to do to test this trivial class would be to use a genuine Runnable class, but if you tried to mock the Class, you would run into the problems you're having. So, you could refactor it thus:
public class PassThruFactory {
public Object newInstance(Class<?> clazz) throws Exception {
return clazz.newInstance();
}
}
public class Instantiator {
private PassThruFactory factory = new PassThruFactory();
public Runnable getNewInstance(Class<Runnable> runnableClass) throws Exception {
return (Runnable)factory.newInstance(runnableClass);
}
}
Now Instantiator does exactly the (trivially simple) thing it was doing before with the same public API and no need for any client of the class to do any special injecting of their own. However, if you wanted to mock the factory class and inject it, that's very easy to do.
why not using an agent if you can't refactor the code there isn't many options, as #jherics mentionned, java system classes are loaded by the bootstrap classloader and powermock can't redefine their bytecode.
However Powermock now coms with an agent, that will allow system classes mock. Check here for complete explanation.
The main idea is to modify your java command and add :
-javaagent: path/to/powermock-module-javaagent-1.4.12.jar
The basic thing this agent is doing is to definalize classes, to allow future mocking in a specific test, that's why you'll need to use specific types to communicate with the agent, for example with JUnit :
#Rule PowerMockRule rule = new PowerMockRule(); // found in the junit4 rule agent jar
TestNG is also supported. Just check the wiki page for more information.
Hope that helps.
First, as stated in the comments, you would need to do:
Class<Runnable> mockRunnableaClass = (Class<Runnable>)mock(Class.class);
But that won't work in the usual way because of a limitation with PowerMock. You cannot simply mock classes in from java.lang, java.net, java.io or other system classes because they're loaded by Java's bootstrap classloader and cannot be byte-code manipulated by PowerMock's classloader. (See PowerMock FAQ #4.) As of PowerMock 1.2.5, you can work around this. If the class you wanted to test was this:
public class ClassToTest {
private Class<Runnable> runnableClass;
public void setRunnableClass(Class<Runnable> runnableClass) {
this.runnableClass = runnableClass;
}
public Runnable foo() {
return runnableClass.newInstance();
}
}
Then you would do this:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ClassToTest.class }) // Prepare the calling class for test
public class SystemClassUserTest {
#Test
public void testFoo() throws Exception {
Class<Runnable> mockClass = (Class<Runnable>) mock(Class.class);
Runnable mockRunnable = mock(Runnable.class);
ClassToTest objectUT = new ClassToTest();
objectUT.setRunnableClass(mockClass);
when(mockClass.newInstance()).thenReturn(mockRunnable);
assertThat(objectUT.foo(), is(sameInstance(mockRunnable);
}
}
How about this. creating a get method of the has a Object (MS) in class PCService and then mock it.
public class PCService implements PCServiceIf {
public MSIf getMS() {
return ms;
}
private MSIf ms = new MS();
public boolean isMovieAccessibleToMyLevel(String myLevel, String movieId) {
return getMS().getPCL(movieId);
}
}
#Test
public void testIsMovieAccessibleToMyLevelMock() {
msMock = mock(MS.class);
spy = spy(new PCService());
doReturn(msMock).when(spy).getMS();
when(msMock.getPCL(movieId)).thenReturn(value);
when(spy.getMS().getPCL(movieId)).thenReturn(value);
assertTrue(spy.isMovieAccessibleToMyLevel("PG", movieId) == true);
}

Categories

Resources