簡體   English   中英

如何測試給定 class 具有 static 方法使用 mockito

[英]how to test given class having static method using mockito

import com.ssctech.eventmsg.app.model.EstimatedCash; 
import com.ssctech.eventmsg.app.properties.KongAPIProperties;
import lombok.extern.slf4j.Slf4j; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Qualifier; 
import org.springframework.stereotype.Service; 
import org.springframework.web.reactive.function.client.WebClient; 

import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;

public class KongAPIService {

    public static final String KONG_REGISTRATION_ID = "kong";

    @Autowired
    @Qualifier("kongApi")
    private WebClient webClient;

    @Autowired
    private KongAPIProperties kongAPIProperties;

    public EstimatedCash getEstimatedCash(String fundSponsorId, String positionId, String transId1, String transId2, String system) {

        try {
            return webClient.get()
                .uri(kongAPIProperties.getCashAvailabilityUri(), positionId, transId1, transId2)
                .attributes(clientRegistrationId(KONG_REGISTRATION_ID))
                .header("authorizationContext", "operator=" + kongAPIProperties.getAuthorizationContext())
                .header("fundSponsorId", fundSponsorId)
                .header("securityChannel", kongAPIProperties.getSecurityChannel())
                .header("system", system)
                .header("tenant", kongAPIProperties.getTenant())
                .retrieve()
                .bodyToMono(EstimatedCash.class)
                .block();
        } catch(Exception e) {
            log.error("Cannot get Cash Availability Info from API for " + "transId1 = " + transId1 + " / " + "transId2 = " + transId2, e);
            return new EstimatedCash();
        }
    }

}

clientRegistrationId(KONG_REGISTRATION_ID)這是 static 方法我無法編寫junit測試此方法如何在不使用PowerMock的情況下使用mockito進行模擬。

package com.ssctech.eventmsg.app.service;

import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.when;
import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatchers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.web.reactive.function.client.WebClient;
import org.mockito.Matchers;

import com.ssctech.eventmsg.app.model.EstimatedCash;
import com.ssctech.eventmsg.app.properties.KongAPIProperties;

import reactor.core.publisher.Mono;

@RunWith(MockitoJUnitRunner.class)
public class KongAPIServiceTest {
    @InjectMocks
    KongAPIService KongApiService;
    @Mock
    WebClient webClient;
    @Mock
    WebClient.RequestBodyUriSpec requestBodyUriSpec;
    @Mock
    WebClient.RequestHeadersUriSpec requestHeadersUriSpec;
    @Mock
    WebClient.RequestHeadersSpec requestHeadersSpec;
    @Mock
    WebClient.RequestBodySpec requestBodySpec;
    @Mock
    WebClient.ResponseSpec responseSpec;
    @Mock
    EstimatedCash estimate;
    @Mock
    Mono mono;
    @Mock
    Consumer<Map<String, Object>> consumer;
    private KongAPIProperties kongAPIProperties=new KongAPIProperties();
    Map<String, Object> mp = new HashMap<>();

    @Before
    public void setup() {
        KongApiService = new KongAPIService();
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void postTest() throws Exception {
        when(webClient.get()).thenReturn(requestHeadersUriSpec);
        kongAPIProperties.setCashAvailabilityUri("available");
        when(requestHeadersUriSpec.uri(Matchers.any(String.class), Matchers.any(String.class), Matchers.any(String.class),
                Matchers.any(String.class))).thenReturn(requestHeadersUriSpec);
//      when(requestHeadersSpec.attributes(consumer)).thenReturn(requestBodySpec);
//      when(requestHeadersSpec.header(Matchers.any(String.class), Matchers.any(String.class)))
//              .thenReturn(requestHeadersSpec);
//      when(requestHeadersSpec.retrieve()).thenReturn(responseSpec);
//      when(responseSpec.bodyToMono(Matchers.any(Class.class))).thenReturn(mono);
//      when(mono.block()).thenReturn(new String());
        assertNotNull(KongApiService.getEstimatedCash("001", "1", "id1", "id2", "mfa"));
    }

}

僅使用mockito來模擬 static 方法是不可能的。

mocking 整個WebClient交互幾乎沒有什么價值,因為您最終得到 mocking 一切,並且實際上是您的實現的副本。 這很脆弱,在重構代碼時無濟於事。

在測試與 HTTP 客戶端交互的 class 時,我建議生成本地 HTTP 服務器並模擬 Z293C9EA246FF989A6 響應。 MockWebServer非常適合此用例或WireMock / MockServer

這些本地模擬服務器中的大多數都允許在之后檢索請求,以便您可以檢查是否存在所有標頭。

對於 static 方法訪問,可以使用 Mockito 模擬該方法(如果需要):

try (MockedStatic<ServerOAuth2AuthorizedClientExchangeFilterFunction> mockedStatic = Mockito.mockStatic(ServerOAuth2AuthorizedClientExchangeFilterFunction.class)) {

  mockedStatic
    .when(() -> ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId(eq("KONG_REGISTRATION_ID")))
    .thenReturn("YOUR_ID");

  // ...
}

如果您仍打算編寫測試並模擬所有內容,請考慮使用深度存根以避免測試中出現大量樣板代碼。

我有同樣的問題。 我找到了解決辦法。 像這樣使用Mockito.notNull()

when(requestBodyMock.attributes(notNull())).thenReturn(requestBodyMock);

我無法對此使用深度存根,這是行不通的。 希望這對其他人有幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM