Is there way to mock for unit test static method in Java without executing the method actual implementation? Actual implementation launches the process that cannot be done in unit test context.
public class MyExecutor {
public static int execute(...) {
Process pr = Runtime.getRuntime().exec(...)
int status = pr.waitFor();
return status;
}
public MyClass {
public void methodToUnitTest(...){
MyExecutor.execute(...)
}
I want to mock MyExecutor.execute and verify both its invocation and its params when unit testing MyClass.methodToUnitTest but without actual execution of this method.
I read that PowerMockito can mock static method but it does not prevent actual implementation from being executed.
Wrap the static class MyExecutor in a non-static class. Extract the methods of your new non-static class into an interface. Replace the dependencies to static class with the interface - use dependency injection to provide MyExecutor instances to MyClass:
public MyExecutorAdapter implements Executor{
public void execute() {
MyExecutor.execute() //call to static code
}
}
public MyClass {
private Executor myExecutor;
public MyClass(Executor myExecutor){ //MyExecutorAdapter instance can be injected here
this.myExecutor = myExecutor;
}
public void methodToUnitTest(...){
myExecutor.execute(...)
}
}
Now, with the interface, you can easily mock or provide a fake implementation for testing purposes. In your case, you probably need to have a mock to check if the execute method was called.
This is basically known as Adapter pattern
Related
I have a test case that mock a static method of java.lang.System class:
#Test
fun `getLocalTime()`() {
// Arrange
val staticMock = Mockito.mockStatic(System::class.java)
Mockito.`when`(System.currentTimeMillis()).thenReturn(1000L)
// Action
val res = deviceTimeProvider.getLocalTime()
// Assert
Truth.assertThat(res).isEqualTo(1000L)
staticMock.close()
}
But when I run the test, I got this error:
org.mockito.exceptions.base.MockitoException: It is not possible to
mock static methods of java.lang.System to avoid interfering with
class loading what leads to infinite loops
Why does this happen? How can I mock methods of java.lang.System class?
While Mockito since 3.4.0 version allows mocking static methods it is not allowed to mock the Thread and System static methods, see this comment on github
Finally note that Mockito forbids mocking the static methods of System (and Thread). Those methods are to much cemented into class loading which happens in the same thread. At some point, we might add instrumentation to class loading to temporarily disable the static mocks within it to make mocking these classes, too, where we also would need to disable their intensification properties. You can however easily mock Instant.now().
If you like ugly solutions you can still mock System with PowerMockito
#PrepareForTest(System.class)
public class TestCase {
#BeforeClass
public void setup() {
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.currentTimeMillis()).thenReturn(1000L);
}
...
But I would avoid mocking System classes if possible. You can still wrap it in method and mock this method.
To mock the static methods of java.lang.System class with the help of Mockito.
Create an interface i.e ISystem.java
public interface ISystem {
String getProperty(String name);
Long getCurrentTimeInMillis();
}
2- Create the implementation class of ISystem interface i.e ISystemImpl.java
public class ISystemImpl implements ISystem {
#Override
public String getProperty(final String name) {
return System.getProperty(name);
}
#Override
public Long getCurrentTimeInMillis() {
return System.currentTimeMillis();
}
}
3- Use Isystem.java inside your DeviceTimeProvider.java class.
public class DeviceTimeProvider {
#NonNull private final ISystem mISystem;
public DeviceTimeProvider(ISystem iSystem){
mIsystem = iSystem;
}
public Long getLocalTime(){
return mIsystem.getCurrentTimeInMillis()
}
}
4- Now finally mock the ISystem interface inside your test class.
public class DeviceTimeProviderTest {
private ISystem mISystem;
private DeviceTimeProvider sut;
#Before
public setup(){
mIsystem = mockito.mock(ISystem.class)
sut = new DeviceTimeProvider(mISystem);
}
#Test
public void getDeviceLocalTime(){
Long expectedTime = 1000L;
mockit.when(mISystem.getCurrentTimeInMillis()).thenReturn(expectedTime);
Long actualTime = sut.getLocalTime();
Assert.assertEquals(actualTime, expectedTime);
}
}
OUTPUT
I have a private method whose invocation I want to test without caring about the arguments. I want to test if it was called at all or not.
MyClass.java
public void doStuff(){
unload(args);
}
private void unload(List<String> args) {
//
}
So I used following:
MyClasstest.java
MyClass myClass = PowerMockito.spy(new MyClass());
myClass.doStuff();
verifyPrivate(myClass, times(1)).invoke("unload",any(List.class));
// verifyPrivate(myClass, times(1)).invoke("unload",any()); //same result with this
This test fails with following exception:
Wanted but not invoked com.MyClass.unload(
null );
However, there were other interactions with this mock .......
(actual values with which it was called)
Can verifyPrivate be called with only actual arguments & not with any()?
Here is a working example of what you are trying to do:
You might just missing the #PrepareForTest annotation, which has to point to the correct class. If your class is an external one use #PrepareForTest(MyClass.class), the example below shows it with an internal class.
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClassTest.class)
public class MyClassTest {
static class MyClass {
public void doStuff(){
unload(null);
}
private void unload(List<String> args) {
}
}
#Test
public void test() throws Exception {
MyClass myClass = PowerMockito.spy(new MyClass());
myClass.doStuff();
PowerMockito.verifyPrivate(myClass, Mockito.times(1)).invoke("unload", Mockito.any());
}
}
Note that you should consider whether you really want to do this in a UnitTest. Normally your UnitTest should not be concerned about whether a private method is used or not, it should be focused on verifying that the correct result is returned or the correct object state is reached.
By adding knowledge about the internal behaviour of the class into it, you test is tightly coupled to the implementation which might not be a good thing.
I am having some trouble writing a unit test for my application. Currently, I am testing class A. In the method of class A I am testing, it makes a call to a helper class's method, which then calls another method inside the same helper class(getKeyObject) whose only function is to call a static method of a class contained in a framework I am using(buildKeyObject()). I am trying to stub getKeyObject() so that it returns a mock of the Object that is normally generated, but I have no idea on how to proceed.
One way I thought was to utilize PowerMockito and use PowerMockito.mockStatic(ClassInFramework.class) method to create a mock of the class in the framework I am using, and then use when(ClassInFramework.buildKeyObject()).thenReturn(KeyObjectMock), but due to some limitations on the work I am doing, I am forbidden to use PowerMockito. I am also unable to use Mockito.spy or the #spy annotation because of the same reasons.
class ATest{
public A aInstance = new A();
#Test
public void test(){
KeyObject keyObjectMock = Mockito.mock(KeyObject.class);
/*
between these 2 lines is more mockito stuff related to the KeyObjectMock above.
*/
String content = aInstance.method1();
Assert.assertEquals(content, "string")
}
}
class A{
public RandomClass d = new RandomClass()
public String method1(){
Helper helper = new Helper();
Object a = helper.method2()
return d.process(a);
}
}
class Helper{
public Object method2(){
KeyObject keyObject = getKeyObject();
Object object = keyObject.getObject();
return object;
}
public KeyObject getKeyObject(){
return ClassInFramework.buildKeyObject(); //static method call.
}
}
Can you guys help me with this?
Constructor injection is one of the common ways to do this. It does require you to modify the class under test for easier testing.
First, instead of creating a new Helper in the method, make it a member variable and assign it in the constructor.
class A {
private Helper helper;
// constructor for test use
public A(Helper helper) {
this.helper = helper;
}
// convenience constructor for production use
public A() {
this(new Helper());
}
}
Now, in your test, you can use the test constructor to inject any mock object derived from Helper. This can be done using Mockito or even simple inheritance.
class MockHelper extends Helper {
// mocked methods here
}
class ATest {
public A aInstance = new A(new MockHelper());
// ...
}
I have a scenario in which I have to mock a method in parent class. The method is invoked from the method under test. I have not been able to mock the function using jMockit.
My super class is method is as follows
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
// Email recipients code. I want to mock this function.
}
}
My subclass is as follows
public class MyClass extends SuperClass {
public void methodUnderTest(HttpServletRequest request) {
// Some code here.
List<String> recipients = new ArrayList<>();
recipients.add("foo#example.com");
recipients.add("bar#example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
I have tried using partial mocks using jMockit's tutorial, but it has not worked for me. My test method is given below.
UPDATE: I implemented Rogerio's suggestion as follows. The implementation still calls the real method. When I debug the instance of mocked class in Eclipse, this is what I see com.project.web.mvc.$Subclass_superClass#6b38c54e
#Test
public void testMethodUnderTest(#Mocked final SuperClass superClass) throws Exception {
final MyClass myClass = new MyClass();
new Expectations(myClass) {{
// .. Other expectations here
superClass.emailRecipients((List<String>) any);
}};
MockHttpServletRequest req = new MockHttpServletRequest();
myClass.methodUnderTest(req);
}
The issue is that when I try to mock the invocation of emailRecipients, it always tries to call the actual function. I am using Java 7, jMockit v1.35, and Maven 3x for our builds.
UPDATE The code is legacy code. As a result, we can't update it. We can not use PowerMock as it is not among the libraries that have been approved by the company. We can use either jMockit or Mockito or a combination of both.
The fact that you want to mock the method from parent class shows that your approach fails the Separation of Concerns/Single responsibility Pattern (SoC/SRP).
The use of PowerMock as suggested by Rajiv Kapoor is possible but this (as any use of PowerMock) would be a surrender to bad design.
You can solve your design problem by applying the Favor Composition over Inheritance principle (FCoI).
To do so you'd change your (most likely) abstract super class into a "normal" class. You'd create an interface that declares all the public and abstract methods in your super class. Your child class would no longer extend the parent class but implement the interface. It would get an instance of the former parent class as dependency and call it's methods providing common behavior as needed.
This dependency can easily mocked without the need of PowerMock.
UPDATE The code is legacy code. As a result, we can't update it.
In that case you are outruled.
The code you have is not unittestable because it is written in an untestable way. Your only chance is to write module and/or acceptance tests (without the use of a mocking framework) covering each and every execution path through your code.
This test will be expensive to create and slow but they will gurad your when refactoring the code to something testable (== changable) later.
see below example
P.S. use Mockito.any(HttpServletRequest.class)instead of Mockito.any(ArrayList.class) for your code
Super Class
public abstract class SuperClass {
protected void emailRecipients(List<String> recipients) {
System.out.println("Emailed!");
}
}
MyClass
public class MyClass extends SuperClass {
public void methodUnderTest() {
// Some code here.
ArrayList<String> recipients = new ArrayList<>();
recipients.add("foo#example.com");
recipients.add("bar#example.com");
// This needs to be mocked.
this.emailRecipients(recipients);
}
}
Test Class
public class TestCase {
MyClass myClass = Mockito.mock(MyClass.class, Mockito.CALLS_REAL_METHODS);
#Before
public void prepare() {
PowerMockito.doNothing().when(myClass).emailRecipients(Mockito.any(ArrayList.class));
/*PowerMockito.doAnswer(new Answer<Void>() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
System.out.println("Custom code");
return null;
}
}).when(myClass).emailRecipients(Mockito.any(ArrayList.class));*/
}
#Test
public void testMethodUnderTest() throws Exception {
myClass.methodUnderTest();
}
}
If you don't want the code in emailRecipients to execute then use doNothing()
else use doAnswer to execute some other code
I have a Mainclass that I need to test which is dependent on other class.
Now I am creating a mock for that class
How to test void methods using easymock
MainClass{
mainClassMethod(){
dependencyClass.returnVoidMethod();
//other code
}
}
TestClass{
#Before
setUpMethod(){
DependencyClass dependencyClassMock = EasyMock.createMock(DependencyClass.class);
}
#Test
testMainClassMethod(){
EasyMock.expect(dependencyClassMock.returnVoidMethod()).andRetur //this is not working
dependencyClassMock.returnVoidMethod();
EasyMock.expectLastCall().anyTimes(); //If I use this, it is invoking the method.
}
}
//My dependency class code
DependencyClass implements ApplicationContextAware{
private static ApplicationContext applicationContext;
private static final String AUTHENTICATION_MANAGER = "authenticationManagers";
returnVoidMethod(){
ProviderManager pm = (ProviderManager) getApplicationContext().getBean(AUTHENTICATION_MANAGER); //this is returning null
}
//othercode
//getters and setters of application context
}
As described in the Easymock Documentation you don't put the method inside an expect() (since there is no return). You can just call the mocked method by itself and if it is in "record" mode then it is implied an expect.
dependencyClassMock.returnVoidMethod();
If you need to throw an Exception or say the method can be called anyTimes() you can use expectLastCall()
#Test
public void testMainClassMethod(){
dependencyClassMock.returnVoidMethod();
EasyMock.expectLastCall().anyTimes();
...
//later to replay the mock
EasyMock.replay(dependencyClassMock);
//now this method is actually called
dependencyClassMock.returnVoidMethod();
}
EDIT : Just noticed that you don't have the dependencyClassMock as field:
public class TestClass{
DependencyClass dependencyClassMock
#Before
setUpMethod(){
dependencyClassMock = EasyMock.createMock(DependencyClass.class);
}
...//rest of class is as described above
#dkatzel
the test is completely wrong..... you are calling manually a method and the you verify if it was called...of course it was! ...that's not the right way (my opinion)
A better way (my opinion) would be to extend the mehod class you would like to test, override that method and in the body just put a boolean variable as a flag to k now if the method was called or not....you don't even need to use EasyMock
Example
Class DependencyClass {
public void returnVoidMethod() {
[.... content ...]
}
}
Class A_test {
#Test
public void checkVoidMethodCalled() {
A_mod obj = new A_mod();
mainClassMethod();
assertTrue(obj.called);
}
Class A_mod extends DependencyClass {
boolean called = false;
#Override
public void returnVoidMethod() {
called = true;
}
}
}
You are welcome.