簡體   English   中英

使用Mockito和jUnit為具有兩個HTTP調用的方法編寫單元測試

[英]Writing a unit test for a method with two HTTP calls with Mockito and jUnit

我有三種方法,

  • void save(String a,String b)
  • String getId(String a,Pojo p)
  • void update(String a,String b,StringEntity c)

以下是實現(不是完整的實現),

String getId(String accessToken, Pojo p) {

    //Note that the pojo is for formatting the payload for the request, nothing more

    HttpResponse response = httpRequestService.makeGetRequest(url, TOKEN_PREFIX, accessToken,
            CONTENT_TYPE);
    if (response.getStatusLine().getStatusCode() == 200) {
        log.debug("Success");
    }

    //Code for getting the id from the response

    return id;
}

void update(String accassToken, String id, StringEntity payload) {

    HttpResponse response = httpRequestService.makePutRequest(url + id,
            TOKEN_PREFIX, accessToken, CONTENT_TYPE, payload);

    if (response.getStatusLine().getStatusCode() == 200) {
        log.debug("Success");
    }
}

void save(String accessToken, String payload) {

    //The getId() is called here
    String id = getId(/*arguments*/);

    if(id == null) {
        log.error("Error");
    } else {
        //The update() is called here
        update(/*arguments*/);
    }
}

如前所述,getId和update方法在save方法中調用,getId和update方法都有HTTP調用。

我必須為save()方法編寫單元測試。 這是我試過的。

    //This is an interface with methods to call HTTP requests.
    HttpRequestService httpRequestService = Mockito.mock(HttpRequestService.class);

    //Constructor injection
    ClassWithMethods a = new ClasswithMethods(httpRequestService);

    HttpResponse responseGet = Mockito.mock(HttpResponse.class);
    StatusLine statusLineGet = Mockito.mock(StatusLine.class);
    HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
    Mockito.when(responseGet.getStatusLine()).thenReturn(statusLineGet);
    Mockito.when(statusLineGet.getStatusCode()).thenReturn(200);
    Mockito.when(responseGet.getEntity()).thenReturn(httpEntity);
    Mockito.when(httpEntity.getContent()).thenReturn(IOUtils.toInputStream(stream));
    Mockito.when(httpRequestService.makeGetRequest(url, TOKEN_PREFIX, accessToken,
            CONTENT_TYPE).thenReturn(responseGet);

    HttpResponse responsePut = Mockito.mock(HttpResponse.class);
    StatusLine statusLinePut = Mockito.mock(StatusLine.class);
    Mockito.when(responsePut.getStatusLine()).thenReturn(statusLinePut);
    Mockito.when(statusLinePut.getStatusCode()).thenReturn(200);
    Mockito.when(httpRequestService.makePutRequest(url + id, TOKEN_PREFIX,
            accessToken, CONTENT_TYPE, payloadEntity).thenReturn(responsePut);

    a.save(accessToken, payload);

但是在測試時,responsePut返回null。 參數也是匹配的。

問題 :如何測試這個調用兩個HTTP方法的save方法?

這可能不是最好的方法。 如果有更好的方法來測試這樣的方法,請建議。

謝謝

請注意,httpRequestService是一個帶有HTTP調用方法的接口,也使用構造函數注入。

您應該將以下內容提取到一個單獨的方法中(PUT也是如此):

HttpResponse response = httpRequestService.makeGetRequest(url, TOKEN_PREFIX, accessToken,
            CONTENT_TYPE);

然后你可以使用mockito來存根該方法:

when(obj.methodGET(...)).thenReturns(...)

請記住 :你的單元測試應該過度的電線來電!

編輯

private HttpResponse get(String url, ...) {
    return httpRequestService.makeGetRequest(url, TOKEN_PREFIX, accessToken,
            CONTENT_TYPE);
}


private HttpResponse put(String url, ...) {
    return httpRequestService.makePutRequest(url + id,
        TOKEN_PREFIX, accessToken, CONTENT_TYPE, payload);
}

接着:

...
when(mockedStatusLineObj.getStatusCode()).thenReturns(200);
HttpResponse mockedGet = mock(HttpResponse.class);
when(mockedGet.getStatusLine()).thenReturns(mockedStatusLineObj);
when(object.get(...)).thenReturns(mockedGet);
when(object.put(...)).thenReturns(...);

關於你的測試方式

實際上,您的測試設置很好,但閱讀起來很復雜。
測試必須保持可讀性和簡單性。
否則理解和維護它變得困難。 你想模擬HttpRequestService
如果您想對您的課程進行unit-test並且不想考慮集成問題,這是一種好方法。
但是,模擬模擬HttpRequestService依賴關系的方式使得代碼不可讀:

HttpResponse responsePut = Mockito.mock(HttpResponse.class);
StatusLine statusLinePut = Mockito.mock(StatusLine.class);
Mockito.when(responsePut.getStatusLine()).thenReturn(statusLinePut);
Mockito.when(statusLinePut.getStatusCode()).thenReturn(200);

並在每次調用時重復此操作。
用一種方法提取它們:

public HttpResponse createMockedHttpResponse(String url){
    HttpResponse responsePut = Mockito.mock(HttpResponse.class);
    StatusLine statusLinePut = Mockito.mock(StatusLine.class);
    Mockito.when(responsePut.getStatusLine()).thenReturn(statusLinePut);
    Mockito.when(statusLinePut.getStatusCode()).thenReturn(200);
    return responsePut;
}

關於測試失敗

它只是在行處拋出NullPointerException

update()方法中的if (response.getStatusLine().getStatusCode() == 200)

當我調試它時,它顯示responsePut為null。

如果我查看您的實際代碼,則在測試的類中進行以下調用:

getStatusLine().getStatusCode()

在這里被正確嘲笑:

HttpResponse responsePut = Mockito.mock(HttpResponse.class);
StatusLine statusLinePut = Mockito.mock(StatusLine.class);
Mockito.when(responsePut.getStatusLine()).thenReturn(statusLinePut);
Mockito.when(statusLinePut.getStatusCode()).thenReturn(200);

通過消除,這意味着沒有遇到下一個語句中記錄的行為:

Mockito.when(httpRequestService.makePutRequest(url + id, TOKEN_PREFIX,
        accessToken, CONTENT_TYPE, payloadEntity).thenReturn(responsePut);

所以確保你備案行為makePutRequest()和實際調用makePutRequest()具有完全相同的/ equals()傳遞的參數。
如果測試邏輯並不真正需要某些參數,請不要猶豫,通過Mockito.any()

暫無
暫無

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

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