Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking private method of class under test using JMockit

I want to mock private method of a class under test but method return false first two times when the method is called after that it should return false. Here is the code what I tried. This is the class which is being tested

public class ClassToTest 
{
    public void methodToTest()
    {
        Integer integerInstance = new Integer(0);
        boolean returnValue= methodToMock(integerInstance);
        if(returnValue)
        {
            System.out.println("methodToMock returned true");
        }
        else
        {
            System.out.println("methodToMock returned true");
        }
        System.out.println();
    }
    private boolean methodToMock(int value)
    {
        return true;
    }
}

Test class

import org.junit.Test;
import static mockit.Deencapsulation.*;

import mockit.*;
public class TestAClass 
{
    @Tested ClassToTest classToTestInstance;
    @Test
    public void test1()
    {

        new NonStrictExpectations(classToTestInstance)
        {
            {
                invoke(classToTestInstance, "methodToMock", anyInt);
                returns(false);
                times = 2;

                invoke(classToTestInstance, "methodToMock", anyInt);
                returns(true);
                times = 1;

            }
        };

        classToTestInstance.methodToTest();
        classToTestInstance.methodToTest();
        classToTestInstance.methodToTest();

    }
}

I did this to get desired results

    final StringBuffer count = new StringBuffer("0");
    new NonStrictExpectations(classToTestInstance)
    {

        {
            invoke(classToTestInstance, "methodToMock", anyInt);
            result= new Delegate() 
            {
                boolean methodToMock(int value)
                {                   
                    count.replace(0, count.length(), Integer.valueOf(Integer.valueOf(count.toString())+1).toString());
                    if(Integer.valueOf(count.toString())==3)
                    {
                        return true;
                    }
                    return false;
                }
            };

        }
    };
like image 787
Varun Avatar asked Jun 26 '14 10:06

Varun


People also ask

Can we mock private methods?

For Mockito, there is no direct support to mock private and static methods. In order to test private methods, you will need to refactor the code to change the access to protected (or package) and you will have to avoid static/final methods.

What is JMockit in Java?

Introduction. First of all, let's talk about what JMockit is: a Java framework for mocking objects in tests (you can use it for both JUnit and TestNG ones). It uses Java's instrumentation APIs to modify the classes' bytecode during runtime in order to dynamically alter their behavior.

What is the difference between JMockit and Mockito?

Mockito uses 'proxy API' design architecture. 7. JMockit is based on Java 1.5 instrumentation API framework. Finally, the JMockit Testing Toolkit has a wider scope and more ambitious goals than other mocking toolkits, in order to provide a complete and sophisticated developer testing solution.


1 Answers

Using Expectations (or StrictExpectations)

Using a combination of Expectations and Deencapsulation.invoke(), you can partially mock the tested object:

import org.junit.Test;
import static mockit.Deencapsulation.*;
import mockit.*;

public class TestAClass
{
    public static class ClassToTest 
    {
        public void methodToTest()
        {
            boolean returnValue = methodToMock(0);
            System.out.println("methodToMock returned " + returnValue);
        }

        private boolean methodToMock(int value) { return true; }
    }

    @Tested ClassToTest classToTestInstance;

    @Test
    public void partiallyMockTestedClass() {
        new Expectations(classToTestInstance) {{
            invoke(classToTestInstance, "methodToMock", anyInt);
            result = false;
            times = 2;
        }};

        classToTestInstance.methodToTest();
        classToTestInstance.methodToTest();
        classToTestInstance.methodToTest();
    }
}

The test above prints:

methodToMock returned false
methodToMock returned false
methodToMock returned true

In general, of course, we should avoid mocking private methods. That said, I have found in practice that it is sometimes useful to do so, typically when you have a private method which does something non-trivial and was already tested by another test; in such a case, mocking that private method in a second test (either for a different public method or a different path through the same public method) may be significantly easier than setting up necessary inputs/conditions.

Using NonStrictExpectations (deprecated in JMockit 1.23)

It's just as easy to write the test with a NonStrictExpectations (the original attempt by the OP didn't work only because the same non-strict expectation was recorded twice, with the second recording overriding the first):

@Test
public void partiallyMockTestedClass() {
    new NonStrictExpectations(classToTestInstance) {{
        invoke(classToTestInstance, "methodToMock", anyInt);
        returns(false, false, true);
    }};

    classToTestInstance.methodToTest();
    classToTestInstance.methodToTest();
    classToTestInstance.methodToTest();
}

Use a Delegate

If more flexibility is needed, we can always record a Delegate-based result:

@Test
public void partiallyMockTestedClass() {
    new NonStrictExpectations(classToTestInstance) {{
        invoke(classToTestInstance, "methodToMock", anyInt);

        result = new Delegate() {
           boolean delegate() {
               boolean nextValue = ...choose next return value somehow...
               return nextValue;
           }
        }
    }};

    classToTestInstance.methodToTest();
    classToTestInstance.methodToTest();
    classToTestInstance.methodToTest();
}
like image 132
Rogério Avatar answered Oct 13 '22 06:10

Rogério