[英]Using Moq to mock HttpClient in the context of Thread
我正在使用moq創建單元測試,但我無法弄清楚如何將此框架應用於我處理使用HttpClient
的程序的一部分。 我發現有各種資源可以演示如何直接模擬HttpClient
響應,但是我的應用程序使用HttpClient
的方式與使用Thread
略有不同。
測試的骨架:
public class MyTestClass
{
public void myTest()
{
ClassA classObj = new ClassA();
classObj.Start();
// I'd like to use moq somewhere here to mock the response that occurs in DoThreadStuff() below
}
}
正在測試的 class:
public class ClassA
{
private readonly Thread _myThread;
private HttpClient _client;
public ClassA()
{
// initialize some values
_myThread = new Thread(DoThreadStuff);
}
public void Start()
{
_myThread.Start(); // starts DoThreadStuff()
}
private void DoThreadStuff()
{
var newClient = getNewHttpClient(); // utility function returns a HttpClient
var response = newClient.GetAsync("/my/api/status/endpoint");
}
}
如您所見,當ClassA.Start()
時,會通過GetAsync
創建和使用一個新的HttpClient
。 為這個構建測試的正確方法是什么? 我是否必須更改現有課程的實施以適應最小起訂量? 有沒有人有非常相似的經驗,我可以看看?
假設您的ClassA
如下所示:
public class ClassA
{
private readonly Thread _myThread;
public ClassA()
{
_myThread = new Thread(DoThreadStuff);
}
public void Start()
{
_myThread.Start();
}
private void DoThreadStuff()
{
var newClient = getNewHttpClient();
var response = newClient.GetAsync("https://httpstat.us//200").GetAwaiter().GetResult();
if(response.StatusCode == HttpStatusCode.OK)
Console.WriteLine("OK");
else if(response.StatusCode == HttpStatusCode.InternalServerError)
Console.WriteLine("Not good");
}
protected virtual HttpClient getNewHttpClient()
{
return new HttpClient();
}
}
getNewHttpClient
調用之后添加了一些虛擬代碼
.GetAwaiter().GetResult()
)調用異步方法並不是一個好主意getNewHttpClient
添加到您的 class 作為protected virtual
,以便能夠輕松覆蓋它現在讓我們創建一個輔助方法來模擬 HttpClient:
public static HttpClient SetupMockClient(HttpResponseMessage response)
{
var mockMessageHandler = new Mock<HttpMessageHandler>();
mockMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(response);
return new HttpClient(mockMessageHandler.Object);
}
讓我們從ClassA
派生來覆蓋getNewHttpClient
方法
internal class VerifiableClassA : ClassA
{
private HttpClient mockedHttpClient;
public VerifiableClassA(HttpClient mockedHttpClient)
{
this.mockedHttpClient = mockedHttpClient;
}
protected override HttpClient getNewHttpClient()
{
return this.mockedHttpClient;
}
}
請注意,您也可以使用最小起訂量來執行此操作,因此您無需引入新的 class 來進行測試。 但在這種情況下, getNewHttpClient
應該是public
。
現在您可以像這樣執行單元測試:
var mockedClient = SetupMockClient(new HttpResponseMessage
{
StatusCode = HttpStatusCode.InternalServerError,
Content = new StringContent("Failure")
});
var sut = new VerifiableClassA(mockedClient);
sut.Start();
您應該考慮使用工廠/存儲庫模式。 它們使測試您的方法變得更容易,因為您可以只注入像 HttpClient 這樣的對象的模擬。 Peter Csala 建議的答案非常骯臟,因為您創建了一個 class,它的唯一目的是在測試中使用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.