Mockito.mockConstruction 不返回模拟对象

Emr*_*rol 6 java junit spring mockito

我不想再使用 powermock 了。因为junit5开始模拟静态类。所以我试图摆脱 powermock 方法。

如您所知,您可以使用whenNew关键字创建类的实例。所以我决定使用“mockConstruction”。但是mockConstruction不会返回模拟对象。它不会进入 try 块内。

这是我的 BeforeEach 方法:

 @BeforeEach
    void setUp() {
        partUnlinkService =
            spy(new PartVideoUnlinkService(part1, part2,
                part3));
    }
Run Code Online (Sandbox Code Playgroud)

这是我的测试方法:

  @Test
    void shouldThrowException() throws Exception {
        //given
        UrlLinkDto urlLinkDto =
            UrlPartLinkDto.builder().callId("333").videoId("5555544").build();
        ArgumentCaptor<UrlPartLinkDto> argumentCaptor = ArgumentCaptor.forClass(UrlPartLinkDto.class);
        //when
        try (MockedConstruction<ObjectMapper> ignoredVariable = mockConstruction(ObjectMapper.class,
            (objectMapper, context) -> {
                //then
                partUnlinkService.unlink(urlLinkDto, false);
                verify(partLogCheckService, times(1)).checkForExistingVideo(
                    urlLinkDto.getVideoId());
                verify(objectMapper, times(1)).writeValueAsString(argumentCaptor.capture());
                Throwable throwable =
                    catchThrowable(() -> objectMapper.writeValueAsString(argumentCaptor.capture()));
                assertThat(throwable).isInstanceOf(JsonProcessingException.class);
            })) {
        } 
    }
Run Code Online (Sandbox Code Playgroud)

任何帮助,将不胜感激。

Eug*_*ene 10

您可以通过MockedConstruction.constructed()方法访问在对象实例化期间创建的模拟。它表示在每个构造函数执行后创建的模拟集合。如果您的对象将被实例化 3 次,MockedConstruction<T>.constructed()则每次实例化将返回 3 个不同的模拟对象。
根据文件MockedConstruction<T>

表示所表示类型的任何对象构造的模拟。在模拟构造的范围内,任何拦截器的调用都将生成一个模拟,该模拟将在生成此范围时按照指定进行准备。也可以通过此实例接收模拟。

下面带有注释的简单实现展示了如何获取模拟MockedConstruction并验证它们:

public class A {
    private final String test;

    public A(String test) {
        this.test = test;
    }

    public String check() {
        return "checked " + this.test;
    }
}

public class TestService {
    public String purchaseProduct(String param) {
        A a = new A(param);
        return a.check();
    }
}

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;

import static org.mockito.Mockito.*;

public class ConstructorMockTest {
    private MockedConstruction<A> mockAController;

    @BeforeEach
    public void beginTest() {
        //create mock controller for all constructors of the given class
        mockAController = Mockito.mockConstruction(A.class,
                (mock, context) -> {
                    //implement initializer for mock. Set return value for object A mock methods
                    when(mock.check()).thenReturn(" Constructor Mock A ");
                });
    }

    @Test
    public void test() {
        //each instantiation of class A will return new mock, which initialized by initializer from beginTest method
        //new mock will be stored to mockAController.constructed() collection of mocks
        A aObject = new A("test");
        //ensure that method check() returns mocked value
        Assertions.assertEquals(aObject.check(), " Constructor Mock A ");
        //get just created mock for class A from controller. It will be first element of mockAController.constructed() collection
        A aMock = mockAController.constructed().get(0);
        //ensure that we get correct mock from mock controller, that it is equal from new created object
        Assertions.assertEquals(aMock, aObject);
        //verify that check method was executed on Mock
        verify(aMock, times(1)).check();

        //create new A object, new mock created and stored to mockAController.constructed()
        A aObject2 = new A("test");
        //ensure that method check() returns mocked value
        Assertions.assertEquals(aObject2.check(), " Constructor Mock A ");
        //get just created mock for class A from controller, it will be second object from constructed collection
        A aMock2 = mockAController.constructed().get(1);
        //ensure that we get correct mock from mock controller, that it is equal from just created A object
        Assertions.assertEquals(aObject2, aMock2);
        //verify that check method was executed on Mock
        verify(aMock2, times(1)).check();

        //Example of testing service which creates A object
        TestService service = new TestService();
        String serviceResult = service.purchaseProduct("test");
        //ensure that service returned value  from A mock
        Assertions.assertEquals(serviceResult, " Constructor Mock A ");
        //get just created mock for class A from controller, it will be third object from constructed collection
        A aMock3 = mockAController.constructed().get(2);
        //verify that check method was executed on Mock
        verify(aMock3, times(1)).check();
    }

    @AfterEach
    public void endTest() {
        mockAController.close();
    }
}
Run Code Online (Sandbox Code Playgroud)

让我们重写您的测试。我没有完整的代码,但我会尝试创建一个带有注释的示例:

    @Test
    void shouldThrowException() throws Exception {
        //given
        UrlLinkDto urlLinkDto =
                UrlPartLinkDto.builder().callId("333").videoId("5555544").build();
        ArgumentCaptor<UrlPartLinkDto> argumentCaptor = ArgumentCaptor.forClass(UrlPartLinkDto.class);

        try (MockedConstruction<ObjectMapper> objectMapperMockedConstruction = mockConstruction(ObjectMapper.class,
                (objectMapper, context) -> {
                     //initialize ObjectMapper mock to throw exception when argumentCaptor will come to writeValueAsString method
                    doThrow(JsonProcessingException.class).when(objectMapper).writeValueAsString(argumentCaptor.capture());
                })) {

            //execute service for testing and catch exception
            Throwable throwable = catchThrowable(() -> partUnlinkService.unlink(urlLinkDto, false));

            //verify that inner service was executed
            verify(partLogCheckService, times(1)).checkForExistingVideo(urlLinkDto.getVideoId());

            //verify that ObjectMapper was instantiated
            Assertions.assertEquals(1, objectMapperMockedConstruction.constructed().size());
            //get mock of ObjectMapper which was instantiated during service execution
            ObjectMapper objectMapper = objectMapperMockedConstruction.constructed().get(0);
            //verify that writeValueAsString was executed
            verify(objectMapper, times(1)).writeValueAsString(argumentCaptor.capture());

            //check that exception is correct
            assertThat(throwable).isInstanceOf(JsonProcessingException.class);
        }
    }
Run Code Online (Sandbox Code Playgroud)