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

Var*_*run 12 java junit unit-testing jmockit mocking

我想模拟一个正在测试的类的私有方法但是方法在调用方法之后首先返回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;
    }
}
Run Code Online (Sandbox Code Playgroud)

考试班

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

    }
}
Run Code Online (Sandbox Code Playgroud)

我这样做是为了获得理想的结果

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

        }
    };
Run Code Online (Sandbox Code Playgroud)

Rog*_*rio 13

使用期望(或严格期望)

使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)

以上测试打印:

methodToMock returned false
methodToMock returned false
methodToMock returned true
Run Code Online (Sandbox Code Playgroud)

当然,一般来说,我们应该避免使用模拟private方法.也就是说,我在实践中发现,这样有时很有用,通常是当你有一个非常重要的私有方法并且已经通过另一个测试进行测试时; 在这种情况下,在第二次测试中模拟私有方法(对于不同的公共方法或通过相同的公共方法的不同路径)可能比设置必要的输入/条件容易得多.

使用NonStrictExpectations(在JMockit 1.23中已弃用)

使用NonStrictExpectations编写测试也很容易(OP的原始尝试不起作用,因为相同的非严格期望被记录两次,第二次记录覆盖了第一次):

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

    classToTestInstance.methodToTest();
    classToTestInstance.methodToTest();
    classToTestInstance.methodToTest();
}
Run Code Online (Sandbox Code Playgroud)

使用代表

如果需要更大的灵活性,我们总能记录一个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();
}
Run Code Online (Sandbox Code Playgroud)


Kau*_*hik 11

这对我有用: -

        new MockUp<ClassToTest>() {
            @Mock
            boolean methodToMock(int value) {
                return true;
            }
        };
Run Code Online (Sandbox Code Playgroud)

  • @Gangnus 私有方法模拟(使用 @Mocked)自 JMockit 1.23 起已停止使用,并且在 1.27 版中使用 `MockUp` 时将受到限制。我的回答是错误的,因为它仍然假设在某些情况下模拟私有方法*可能*有用;但事实并非如此。 (2认同)
  • 许多人想找到如何模拟私有方法。其中 12 人甚至在这里投票支持了一些答案。对于我来说,我寻找解决方案,因为我需要它。我找到了。怎么能说没人需要呢?你的答案的问题是不同的——它太复杂了,而显然人们需要简单的东西。它声明部分模拟提供完整模拟。我相信您是该主题的出色专家。但对我来说你的解释太复杂了。 (2认同)
  • JMockit 似乎在嘲笑私有方法方面改变了主意。不管我们对此有何个人看法,也许这应该在主要版本中完成?关于测试私有方法的主题,我的观点是,有大量(遗留)代码需要我们有效地编写*表征*测试 - 模拟私有方法是一个非常有用的功能。我将 JMockit 视为处理这些情况的首选工具 - 无论当前的编程最佳实践概念如何,任何东西都可以被嘲笑。 (2认同)