Сделайте с Mockit что-то вроде MockUp от JMockit - PullRequest
0 голосов
/ 25 октября 2019

Я хочу сделать что-то похожее на 'MockUp' из JMockit, но с Mockito.

Я хочу управлять компиляцией метода класса, который расширяет класс, который я хочу протестировать. Но у меня есть одна проблема, которая заключается в том, что метод является частным, поэтому я думаю, что не могу использовать Mockito, и мне нужно использовать PowerMock.

Проблема

Class A extends B{...}

Class B {
  private Header generateHeaderForServiceCall(c,d,f,g,h,j){...}
} 

В моем классе ATest {In @Прежде чем я хочу издеваться над generateHeaderForServiceCall (.....), просто верните заголовок по умолчанию, созданный для меня. }

Итак, использование JMockit похоже на:

new MockUp<Controller>() {
  @Mock
  private Header generateHeaderForServiceCall(...) {
    return defaultHeader;
 }
};

Я лучше укажу свой контекст:

public class B {
    private Header generateHeaderForServiceCall(Input A, Input B, Input c, Input D) throws ServiceException {
......
//do stuff
return header} 
}


public class A extends B {
    @Override
    public Response process(Request request) throws SOAException {
               //do stuff
        try {
            method_i_want_to_test(Input A, Input B);

            } catch (Exception t) {
                  throwCorrectException(t, logger);
     }
        return response;
 }

    protected Dossier method_i_want_to_test(Input A, Input B) throws 
       SOAException {
        ... //do stuff
        **Header** **header** = generateHeaderForServiceCall(Input A, Input 
             B,Input c, Input D);**

         // **doLogic** with header returned and return the result
    }
}

Что я пытаюсь сделать:

private A aTest;
    @Before
    public void setUp() throws Exception {

        PowerMockito.mock(aTest);

 PowerMockito.doReturn(defaultHeader).when(aTest,"generateHeaderForServiceCall", params);
    }

Итак, когда я иду в method_i_want_to_test и вызываю generateHeaderForServiceCall, я просто хочу получить заголовок по умолчанию и игнорировать входные данные и логику метода. Я хочу издеваться над этим методом, но он частный / защищенный.

  • Итак, могу ли я сделать с Mockito?

  • Нужно ли мнеиспользовать PowerMock?

  • Могу ли я использовать Mockito и PowerMockit вместе?

-------------------------------------- ОБНОВЛЕНИЕ ------------------------------

Итак, мой classA, который я хочу проверить, состоит в следующем:

    package mypackage;

    import package.ClassB;

    @Service
    public class ClassA extends ClassB implements Xinterface {


        @Inject
        public ClassA(InputA inputA,  InputB inputB,InputC inputC,  InputD inputD) {
            ...
        }

        @Override
        public ClassAResponse process(ClassARequest request) throws SOAException {
            ClassAResponse response = initResponse(inputA, request, new ClassAResponse());
            ClassAInput input = request.getInput();
            ClassAOutput output = new ClassAOutput();
            response.setOutput(output);

            try {

                /*  */
                method_i_want_to_test(request.getHeader(), numberInput);

            } catch (Exception t) {
                throwCorrectException(t, logger);
            }
            return response;
        }

        protected Dossier method_i_want_to_test(Header srcHeader, Long numberInput) throws SOAException {

            Header header = generateHeaderForServiceCall(inputA,srcHeader,inputF,inputJ,inputK);

            OtherServiceRequest request = new OtherServiceRequest();
            OtherServiceInput input = new OtherServiceInput();
            input.setNumber(numberInput);
            request.setInput(input);
            request.setHeader(header); // So, you can see the i need the result of generateHeaderForServiceCall method

            OtherServiceResponse response = OtherService.process(request);
            assertSucessfullResponse(response, "OtherService");

            return response;

        }

    }

Мой ClassB, который содержит закрытые и защищенные методы, таков:

    package otherPackage;
    ...

    public class ClassB {

        private Header generateHeaderForServiceCall(InputA inputA,Header srcHeader,InputF inputF,InputJ inputJ,InputK inputK) throws ServiceException {

            String[] nameInfo = QNameUtil.getServiceQNameInfo(inputA);

            String serviceVersion = auxMethod(inputJ, inputF);

            //... do more stuff

            return result;
        }
    }

И мой класс тестирования, где я тестирую частные методы с PowerMock и пробую с Mockito, если метод защищен. После этого я объясню, что я получил при запуске обоих тестов:

    package package;

    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.InjectMocks;
    import org.mockito.Mock;
    import org.mockito.MockitoAnnotations;
    import org.powermock.api.mockito.PowerMockito;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.junit4.PowerMockRunner;
    import static org.powermock.api.mockito.PowerMockito.doReturn;

    @RunWith(PowerMockRunner.class)
    @PrepareForTest(ClassA.class)
    public class MyTest {

        @InjectMocks
        private ClassA classA;
        @Mock
        private InputA inputA;
        @Mock
        private InputB inputB;
        @Mock
        private InputC inputC;
        @Mock
        private InputD inputD;

        @Before
        public void setUp() throws Exception {
            MockitoAnnotations.initMocks(this);
            classA = new classA( inputA,  inputB,inputC,  inputD);
        }

        @Test
        public void processPrivateMethod() throws Exception{
            defaultHeader = Aux.createDefaultHeader();

            //create the spy of my ClassA
            classA spy = PowerMockito.spy(classA);
            // Define what I want the method 'generateHeaderForServiceCall' returns when called
            doReturn(defaultHeader).when(spy, "generateHeaderForServiceCall", inputA,defaultHeader,inputF,inputJ,inputK);

            // I try to call the method 'method_i_want_to_test' with classA variable @Injected and with spy of ClassA
            //classA.method_i_want_to_test(defaultHeader,inputNumber);
            spy.method_i_want_to_test(defaultHeader,inputNumber);

        }
    }

1 - когда я запускаю этот тест, processPrivateMethod в методе отладки, когда generateHeaderForServiceCall вызывается, он пытается выполнить логику метода и терпит неудачу, потому что заголовок является базовым. Но я пытаюсь сделать это и просто вернуть заголовок по умолчанию без логики.

2 - Если я изменю generateHeaderForServiceCall для защищенного типа некоторых методов ClassB, и для этого использую mockito:

    @Test
        public void processProtectedMethod() throws Exception{
            defaultHeader = JUnitTestUtil.createDefaultHeader();
            when(classA.generateHeaderForServiceCall(inputA,defaultHeader,"ccccccc","dxdx",5464564)).thenReturn(defaultHeader);

            classA.method_i_want_to_test(defaultHeader,inputNumber);

        }

Но он возвращает ошибку, потому что методзащищен (та же ошибка, если он частный, и я использую mockito).

Ошибка: java: generateHeaderForServiceCall (....) имеет защищенный доступ в пакете

Попытки:

@Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        // Partial mock to mock methods in parent class
        child = new ClasseA(...){
            @Override
            protected Header generateHeaderForServiceCall(...) throws ServiceException {
                //mock logic here
                return aux.createDefaultHeader();;
            }
        };
    }

    @Test
    public void processPrivateMethod() throws Exception{
        defaultHeader = aux.createDefaultHeader();


        //when
        Dossier bdoo = child.method_i_want_to_test(...);

    } 

2-

@Test
    public void processPrivateMethod() throws Exception{
        defaultHeader = JUnitTestUtil.createDefaultHeader();

        child = PowerMockito.spy(new ClasseA(...));


       PowerMockito.doReturn(defaultHeader).when(child, "generateHeaderForServiceCall", context,defaultHeader,"ccccccc","dxdx",5464564);

        //when
        Dossier bdoo = child.method_i_want_to_test(...);
    }

3-

@Test
    public void processPrivateMethod() throws Exception{
        defaultHeader = JUnitTestUtil.createDefaultHeader();

        child = PowerMockito.spy(new ClassA(...));

        father = PowerMockito.spy(new ClasseB());

        PowerMockito.doReturn(defaultHeader).when(father, "generateHeaderForServiceCall", context,defaultHeader,"ccccccc","dxdx",5464564);

        //when
        Dossier bdoo = child.method_i_want_to_test(...);
    }

Никто не делает то, что я хочу. Все идут в метод generateHeaderForServiceCall в классе B и пытаются сделать логику внутри. Спасибо

1 Ответ

0 голосов
/ 26 октября 2019

Звучит так, как будто вы ищете spy.


Итак, я могу сделать с Mockito? Нужно ли мне использовать PowerMock?

Если он закрыт, вам нужно использовать PowerMockito, если только защищенный Mockito справится с этим.

Могу ли я использоватьMockito и PowerMockito вместе?

PowerMockito основан на Mockito, так что да.


Обратите внимание, что spy следует использовать экономно, например, для тестированияустаревший код. Обычной рекомендацией будет рефакторинг вашего кода.

В аннотацию @PrepareForTest необходимо включить class, где в этом случае изменяется байт-код Class A.


Приватный метод насмешки с PowerMockito и JUnit4:

Вот упрощенный пример с использованием возврата String вместо Header:

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Spy;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(Test.A.class)
public class Test {

    static class A extends B {
        public String process() {
            return "y" + method_i_want_to_test();
        }
    }

    static class B {
        private String generateHeaderForServiceCall() {
            return "abc";
        }

        protected String method_i_want_to_test() {
            return "x" + generateHeaderForServiceCall();
        }
    }

    @Spy
    A classUnderTest = new A();

    @Test
    public void testCustomExceptionIsThrown() throws Exception {

        PowerMockito.doReturn("123").when(classUnderTest, "generateHeaderForServiceCall");
        Assert.assertEquals("yx123", classUnderTest.process());
    }
}

Защищенный метод насмешек с Mockito и JUnit5:

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class Test {

    static class A extends B {
        public String test() {
            return generateHeaderForServiceCall();
        }
    }

    static class B {
        protected String generateHeaderForServiceCall() {
            return "abc";
        }
    }

    @Spy
    A classUnderTest;

    @Test
    public void testCustomExceptionIsThrown() throws Exception {

        Mockito.when(classUnderTest.generateHeaderForServiceCall()).thenReturn("123");
        Assertions.assertEquals("123", classUnderTest.test());
    }
}
...