Thursday, September 10, 2015

How to invoke an object’s private method in Java

The private methods are designed not accessible from outside. But sometimes we want to call it directly, for example in unit testing. Java actually provides ways to call private method with the help of reflection, java.lang.reflect.Method

PowerMock, a widely used mock library also provide helper class to make it easy  in JUnit test cases. (PowerMock indeed wraps the reflection for you)

In this demo, there is a HellowWorld class under test.

package com.shengwang.demo;

public class HelloWorld {

private String sayHello(String name) {
return = "Dear " + name;
}
}

The private method sayHello will be tested in JUnit test case.


1. Method-1 Using reflection directly


  1. 1 What you need

  • JDK  (no third party library is required )

  1.2 Invoke private method in testcase

package com.shengwang.demo;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.junit.Test;


public class HelloWorldByReflectionTest {

@Test
public void testPrivateMethod() {
try {
HelloWorld helloWorld = new HelloWorld();
Method method;
// get reflected method
method = HelloWorld.class.getDeclaredMethod("sayHello",new Class[] { String.class });
// change accessiblity
method.setAccessible(true);
// invoke the method
assertEquals("Dear Tom", method.invoke(helloWorld, "Tom"));
} catch (NoSuchMethodException | SecurityException |
IllegalAccessException | IllegalArgumentException |
InvocationTargetException e) {
e.printStackTrace();
fail();
}
}
}

2. Method-2 Using PowerMock


  2. 1 What you need

  • Mockito
  • PowerMock

PowerMock usually need to work with either Mockito or EasyMock, you can choose anyone. In this demo Mockito is used.

2.2 Add Maven dependencies


Add dependencies to the maven pom.xml

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5.6</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5.6</version>
<scope>test</scope>
</dependency>

  2.3 Invoke private method in testcase

package com.shengwang.demo;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.powermock.reflect.Whitebox.invokeMethod;

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({ HelloWorld.class })
public class HelloWorldByPowerMockTest {
@Test
public void testPrivateMethod() {
String result;
try {
HelloWorld helloWorld = new HelloWorld();
result = invokeMethod(helloWorld, "sayHello", "Tom");
assertEquals("Dear Tom", result);
} catch (Exception e) {
e.printStackTrace();
fail();
}
}
}

The org.powermock.reflect.Whitebox.invokeMethod from PowerMock is imported at the beginning and used to invoke private method.

0 comments:

Post a Comment

Powered by Blogger.

About The Author

My Photo
Has been a senior software developer, project manager for 10+ years. Dedicate himself to Alcatel-Lucent and China Telecom for delivering software solutions.

Pages

Unordered List