HttpClient арқылы external API calls жасайтын services үшін unit tests жазғанда, біздің simplified ArticleService example ішінде real API calls mocks-пен ауыстыру керек.
public class ArticleService(IHttpClientFactory httpClientFactory)
{
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
public async Task<Article?> GetLastArticle()
{
var client = _httpClientFactory.CreateClient("ArticleApi");
using var response = await client.GetAsync("lastarticle");
if (!response.IsSuccessStatusCode)
{
// Optionally log or handle the error here
return null;
}
var responseJson = await response.Content.ReadAsStringAsync();
var article = JsonSerializer.Deserialize<Article>(responseJson);
return article;
}
}
Мысалы NSubstitute арқылы IHttpClientFactory interface mock жасау alone жеткіліксіз. HttpMessageHandler-ден inherit ететін MockHttpMessageHandler class жасау керек.

internal class MockHttpMessageHandler(HttpResponseMessage responseMessage) : HttpMessageHandler
{
private readonly HttpResponseMessage _responseMessage = responseMessage;
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
return Task.FromResult(_responseMessage);
}
}
MockHttpMessageHandler constructor ішінде HttpResponseMessage қабылдайды, яғни mock-тен күтілетін message, және оны overridden SendAsync method ішінде жай return етеді.

Source: HTTP Message Handlers in ASP.NET Web API
Successful Response тестілеу
public class ApiServiceTests
{
[Fact]
public async Task GetLastArticle_ReturnsArticle()
{
// Arrange
var expectedArticle = new Article { Id = 1, Title = "Test Title", Body = "Test Body" };
var jsonResponse = JsonSerializer.Serialize(expectedArticle);
var httpResponse = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(jsonResponse)
};
var mockHttpMessageHandler = new MockHttpMessageHandler(httpResponse);
var httpClient = new HttpClient(mockHttpMessageHandler)
{
BaseAddress = new Uri("https://example.com/")
};
var mockHttpClientFactory = Substitute.For<IHttpClientFactory>();
mockHttpClientFactory.CreateClient("ArticleApi").Returns(httpClient);
var articleService = new ArticleService(mockHttpClientFactory);
// Act
var result = await articleService.GetLastArticle();
// Assert
Assert.NotNull(result);
Assert.Equal(expectedArticle.Id, result.Id);
Assert.Equal(expectedArticle.Title, result.Title);
}
}
HttpClient жасағанда constructor ішіне MockHttpMessageHandler class instance береміз және осы HttpClient мәнін mockHttpClientFactory instance ішіндегі CreateClient method return value етеміз.
Mock-ты flexible ету
Mock-ты SendAsync method ішінде called болатын Func delegate арқылы more flexible етуге болады.
public class MockHttpMessageHandler(
Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> sendAsyncFunc)
: HttpMessageHandler
{
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>>
_sendAsyncFunc = sendAsyncFunc;
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return await _sendAsyncFunc(request, cancellationToken);
}
}
Бұл жағдайда HTTP requests кезінде болатын exceptions тестілеуге болады.
[Fact]
public async Task GetLastArticle_ThrowsHttpRequestException()
{
// Arrange
var mockHttpMessageHandler = new MockHttpMessageHandler(
(r, ct) => throw new HttpRequestException());
var httpClient = new HttpClient(mockHttpMessageHandler)
{
BaseAddress = new Uri("https://example.com/")
};
var mockHttpClientFactory = Substitute.For<IHttpClientFactory>();
mockHttpClientFactory.CreateClient("ArticleApi").Returns(httpClient);
var articleService = new ArticleService(mockHttpClientFactory);
// Act & Assert
await Assert.ThrowsAsync<HttpRequestException>(() => articleService.GetLastArticle());
}
Нәтижесінде external dependencies қолданбай HttpClient mock жасаудың simple way аламыз, әрі expected HTTP responses flexible configuration жасауға болады.