Насмешливый закрытый метод тестируемого класса с использованием JMockit

Я хочу смоделировать закрытый метод тестируемого класса, но метод возвращает 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;
    }
}

Тестовый класс

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

    }
}

Я сделал это, чтобы получить желаемые результаты

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

        }
    };

3 ответа

Решение

Использование ожиданий (или StrictExpectations)

Используя комбинацию 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();
    }
}

Тест выше печатает:

methodToMock returned false
methodToMock returned false
methodToMock returned true

В общем, конечно, надо избегать насмешек 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();
}

Используйте делегата

Если требуется большая гибкость, мы всегда можем записать 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();
}

Это работает для меня:-

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

Здесь вы можете переопределить конкретный метод класса тестирования с помощью фиктивного поведения.

Для приведенного ниже кода:

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

Тестовый класс будет:

public class ClassToTestTest{

    @Test
    public void testMethodToTest(){

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

        ....    

    }
}
Другие вопросы по тегам