Mockito.mockConstruction 不 return 模拟对象

Mockito.mockConstruction does not return the mocked object

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

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

这是我的 BeforeEach 方法:

 @BeforeEach
    void setUp() {
        partUnlinkService =
            spy(new PartVideoUnlinkService(part1, part2,
                part3));
    }

这是我的测试方法:

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

如有任何帮助,我们将不胜感激。

我想我和你有同样的问题,希望有人能解决我们的问题。

在我的例子中,我也想得到一个 return 对象,比如 PowerMock.whenNew().withArguments().thenReturn(someThing),我尝试了很多次但都失败了。 我认为 mockConstruction 只是可以模拟他们的行为,不能像 powerMock 那样验证他们的结果,而且我找不到任何文章或答案。 下面是我的 post link :

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

Represents a mock of any object construction of the represented type. Within the scope of the mocked construction, the invocation of any interceptor will generate a mock which will be prepared as specified when generating this scope. The mock can also be received via this instance.

下面带有注释的简单实现显示了如何从 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();
    }
}

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

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