Java 使用 JMockit 模拟被测类的私有方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24427685/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 12:07:37  来源:igfitidea点击:

Mocking private method of class under test using JMockit

javaunit-testingjunitmockingjmockit

提问by Varun

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

我想模拟一个被测类的私有方法,但是当该方法被调用时,方法前两次返回 false ,然后它应该返回 false。这是我尝试过的代码。这是正在测试的类

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;
                }
            };

        }
    };

采纳答案by Rogério

Using Expectations (or StrictExpectations)

使用期望(或 StrictExpectations)

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

使用 Expectations 和 Deencapsulation.invoke() 的组合,您可以部分模拟测试对象:

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 privatemethods. That said, I have found in practice that it issometimes 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.

一般来说,当然,我们应该避免嘲笑private方法。这就是说,我在实践中发现,它有时是有用的话,通常当你有哪些做了不平凡的,并已经由另一个测试测试的私有方法; 在这种情况下,在第二个测试中模拟该私有方法(对于不同的公共方法或通过相同公共方法的不同路径)可能比设置必要的输入/条件容易得多。

Using NonStrictExpectations (deprecated in JMockit 1.23)

使用 NonStrictExpectations(在 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):

使用 NonStrictExpectations 编写测试也同样容易(OP 的最初尝试并没有奏效,因为相同的非严格期望被记录了两次,第二次记录覆盖了第一次):

@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:

如果需要更多的灵活性,我们总是可以记录一个Delegate基于 - 的结果:

@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();
}

回答by Kaushik

This works for me:-

这对我有用:-

        new MockUp<ClassToTest>() {
            @Mock
            boolean methodToMock(int value) {
                return true;
            }
        };

回答by Amit Kaneria

Here, you can over-ride a particular method of the testing class with mock behavior.

在这里,您可以使用模拟行为覆盖测试类的特定方法。

For the below code:

对于以下代码:

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 would be:

测试类将是:

public class ClassToTestTest{

    @Test
    public void testMethodToTest(){

        new Mockup<ClassToTest>(){
            @Mock
            private boolean methodToMock(int value){
                return true;
            }
        };

        ....    

    }
}