mockito junit5没有模拟java.net.http.HttpClient.send

ttcibm8c  于 2023-05-22  发布在  Java
关注(0)|答案(1)|浏览(136)

我正在尝试在一个javamaven项目(而不是springboot项目)中编写junit 5代码,它调用API并提取响应并创建文件。但是当我试图模拟API调用时,junit仍然调用实际的API,这不是我们想要的行为。有人可以帮助确定这里的问题吗?
我按照这个链接写下面的单元测试How to mock HttpClient's send method in junit 5?
实际服务代码-

public class MyService {

    public void create(String apiHost, String firstPage) {
        HttpClient httpClient = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_2)
                .connectTimeout(Duration.ofSeconds(30))
                .build();
        HttpRequest httpRequest = getHttpRequest(apiHost, firstPage);
 
        MyResponse myResponse = invokeApi(httpClient, httpRequest);
        List<ResponseData> responseDataList = new ArrayList<>(myResponse.getData());
        while (null != myResponse.getLinks().getNext()) {

            myResponse = invokeApi(httpClient, getHttpRequest(apiHost, invokeApi.getLinks().getNext()));
            locationDetailsList.addAll(invokeApi.getData());
        }

        createFile(fileName, responseDataList);
    }

    private HttpRequest getHttpRequest(String apiHost, String pageUri) {
        return HttpRequest.newBuilder()
                .header("Content-Type", "application/json")
                .GET()
                .uri(URI.create(apiHost + pageUri))
                .build();
    }

    @SneakyThrows
    MyResponse invokeApi(HttpClient httpClient, HttpRequest httpRequest) {
        HttpResponse<Supplier<MyResponse>> result = httpClient.send(httpRequest, new JsonBodyHandler<>(MyResponse.class));
        return result.body().get();
    }

    @SneakyThrows
    void createFile(String fileName, List<ResponseData> responseDataList) {
        Path filePath = Paths.get("test/path" + fileName);
        Files.createFile(filePath);
        Files.writeString(filePath, header + System.lineSeparator(), StandardOpenOption.APPEND);
        for (ResponseData responseData : responseDataList) {
            Files.writeString(filePath, responseData + System.lineSeparator(), StandardOpenOption.APPEND);
        }
    }

第5号代码-

class MyServiceTests {

    @InjectMocks
    private MyService myService;

    @Mock
    private HttpClient httpClient;
    @Mock
    HttpResponse<Object> httpResponse;

    @Mock
    private HttpRequest request;

    @BeforeEach
    void setUp() {
        initMocks(this);
        httpClient = mock(HttpClient.class);
        httpResponse = mock(HttpResponse.class);
    }

    @Test
    void testSendMessage() throws Exception {
        MyResponse myResponse=new MyResponse();

        when(httpClient.send(any(),any())).thenReturn(httpResponse);
        when(myService.invokeApi(httpClient,request)).thenReturn(myResponse);
        myService.create("https://test.com", "/v1/test?page_size=100");
        verify(httpClient).send(request, HttpResponse.BodyHandlers.ofString());
    }
}

在上面的junit代码中,当执行“myService.createmyMnt”时,它实际上尝试调用https://test.com,而不是模拟调用。

lnvxswe2

lnvxswe21#

你面临这个问题是因为你模拟了两次相同的依赖。我的意思是:

@Mock
 private HttpClient httpClient;

然后在每个你再次嘲笑你的依赖

httpClient = mock(HttpClient.class);

我建议选择你需要的方法,不要模仿2次。在这里,你是嘲笑和使用@InjectMocks。我们还需要添加注解@ExtendWith(MockitoExtension.class),这将处理initMocks(this),我们不需要添加它(这个注解有助于正确注入模拟)。

@ExtendWith(MockitoExtension.class)
class MyServiceTests {

    @InjectMocks
    private MyService myService;

    @Mock
    private HttpClient httpClient;
    @Mock
    HttpResponse<Object> httpResponse;

    @Mock
    private HttpRequest request;

    @Test
    void testSendMessage() throws Exception {
        MyResponse myResponse=new MyResponse();

        when(httpClient.send(any(),any())).thenReturn(httpResponse);
        when(myService.invokeApi(httpClient,request)).thenReturn(myResponse);
        myService.createmyMnt("https://test.com", "/v1/test?page_size=100");
        verify(httpClient).send(request, HttpResponse.BodyHandlers.ofString());
    }
}

或使用构造函数注入,如:

class MyServiceTests {

    private MyService myService;
    private HttpClient httpClient;
    private HttpResponse<Supplier<MyResponse>> httpResponse;
    private HttpRequest request;

    @BeforeEach
    void setUp() {
        httpClient = mock(HttpClient.class);
        httpResponse = mock(HttpResponse.class);
        request = mock(HttpRequest.class);
        myService = new MyService();
    }

    @Test
    void testSendMessage() throws Exception {
        MyResponse myResponse = new MyResponse();

        when(httpClient.send(any(), any())).thenReturn(httpResponse);
        when(httpResponse.body()).thenReturn(() -> myResponse);

        myService.create("https://test.com", "/v1/test?page_size=100");

        verify(httpClient).send(request, new JsonBodyHandler<>(MyResponse.class));
    }
}

请试试这个:

@Test
void testSendMessage() throws Exception {
    MyResponse myResponse = new MyResponse();

    when(httpClient.send(any(), any())).thenReturn(httpResponse);
    when(httpResponse.body()).thenReturn(myResponse);  // Mock the body() method

    myService.create("dummyURL", "dummyPage");

    verify(httpClient).send(eq(request), any(JsonBodyHandler.class));
}

相关问题