Func<HttpRequestMessage> 相关的单元测试模拟问题
Func<HttpRequestMessage> related Mocking Questions for Unit Tests
我在我的 XUnit 测试中使用了 Moq。在依赖方法中,它包含一个 Func<HttpResponseMessage>
参数。这是我写的单元测试:
[Fact]
public async Task Test()
{
//Arrange
var content = new StringContent(TestData.GetResponse().ToString(), Encoding.UTF8, "application/json");
var httpResponse = new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = content
};
_mockRetryHttpRequest.Setup(x => x.ExecuteAsync(It.IsAny<Func<HttpRequestMessage>>(), It.IsAny<HttpClient>(), It.IsAny<int>()))
.ReturnsAsync(httpResponse);
var libraryService = new LibraryService(_mockRetryHttpRequest.Object);
//Act
var response = await libraryService.GetResponseForSearch(new SearchRequest(), null);
//Assert
response.Should().NotBeNull();
}
这是我需要测试的实际方法
public class LibraryService : ILibraryService
{
private IRetryHttpRequest _retryHttpRequest;
public LibraryService(IRetryHttpRequest retryHttpRequest)
{
_retryHttpRequest = retryHttpRequest;
}
public async Task<ResponseModel> GetResponseForSearch(SearchRequest searchRequest, HttpClient client)
{
//send request and retry if failed
ResponseModel result = new ResponseModel();
HttpResponseMessage httpResponseMessage = await _retryHttpRequest.ExecuteAsync(() => new HttpRequestMessage(), client, 3);
//process response
if (httpResponseMessage != null)
{
string response = await httpResponseMessage.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<ResponseModel>(response);
}
return result;
}
}
public class RetryHttpRequest : IRetryHttpRequest
{
public async Task<HttpResponseMessage> ExecuteAsync(Func<HttpRequestMessage> requestMessage, HttpClient client, int maxTryValue)
{
var content = new StringContent("From Execute Async", Encoding.UTF8, "application/json");
var httpResponse = new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = content
};
return httpResponse;
}
}
当我单步执行代码时,对于下面这行代码,httpResponseMessage
变量返回 null
,尽管我已经在单元测试中用 200 响应模拟了它。
HttpResponseMessage httpResponseMessage = await _retryHttpRequest.ExecuteAsync(() => new HttpRequestMessage(), client, 3);
虽然问题似乎缺乏完整的解释,但以下内容用于演示目的,以展示如何使用最小起订量测试目标方法。
假设如下
public interface IRetryHttpRequest {
Task<HttpResponseMessage> ExecuteAsync(Func<HttpRequestMessage> requestMessage, HttpClient client, int maxTryValue);
}
public class LibraryService : ILibraryService {
private IRetryHttpRequest _retryHttpRequest;
public LibraryService(IRetryHttpRequest retryHttpRequest) {
_retryHttpRequest = retryHttpRequest;
}
public async Task<ResponseModel> GetResponseForSearch(SearchRequest searchRequest, HttpClient client) {
//send request and retry if failed
ResponseModel result = new ResponseModel();
HttpResponseMessage httpResponseMessage = await _retryHttpRequest.ExecuteAsync(() => new HttpRequestMessage(), client, 3);
//process response
if (httpResponseMessage != null) {
string response = await httpResponseMessage.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<ResponseModel>(response);
}
return result;
}
}
public interface ILibraryService {
}
请注意语法更改,这些更改会显示问题中显示的原始代码的错误。
以下测试演示了如何测试 LibraryService.GetResponse
方法并断言预期行为
public async Task SampleTest() {
//Arrange
var content = new StringContent("{}", Encoding.UTF8, "application/json");
var httpResponse = new HttpResponseMessage() {
StatusCode = HttpStatusCode.OK,
Content = content
};
var _mockRetryHttpRequest = new Mock<IRetryHttpRequest>();
_mockRetryHttpRequest
.Setup(_ => _.ExecuteAsync(It.IsAny<Func<HttpRequestMessage>>(), It.IsAny<HttpClient>(), It.IsAny<int>()))
.ReturnsAsync(httpResponse);
var lgService = new LibraryService(_mockRetryHttpRequest.Object);
//Act
var response = await lgService.GetResponseForSearch(new SearchRequest(), null);
//Assert
response.Should().NotBeNull();
}
FluentAssertions 用于断言预期行为。
一些注意事项
仅向被测对象提供了执行测试实际需要的依赖项。这意味着 mock
实际上不需要 HttpClient
被测方法也需要等待才能得到断言响应
因为我无权访问您的测试数据,所以我使用一个空的 JSON 对象“{}”来表示响应的内容以允许 JsonConvert
工作
然后我建议您查看正在反序列化的测试数据。这可能是失败点,因为这是唯一可以将 result
设置为 null
的地方,因为它是在函数顶部初始化的。
你不应该让你的测试方法异步。使其同步,然后执行以下操作而不是等待:
var task = lgService.GetResponseForSearch(new SearchRequest(), null);
task.Wait();
var response = task.Result;
response.Should().NotBeNull();
我在我的 XUnit 测试中使用了 Moq。在依赖方法中,它包含一个 Func<HttpResponseMessage>
参数。这是我写的单元测试:
[Fact]
public async Task Test()
{
//Arrange
var content = new StringContent(TestData.GetResponse().ToString(), Encoding.UTF8, "application/json");
var httpResponse = new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = content
};
_mockRetryHttpRequest.Setup(x => x.ExecuteAsync(It.IsAny<Func<HttpRequestMessage>>(), It.IsAny<HttpClient>(), It.IsAny<int>()))
.ReturnsAsync(httpResponse);
var libraryService = new LibraryService(_mockRetryHttpRequest.Object);
//Act
var response = await libraryService.GetResponseForSearch(new SearchRequest(), null);
//Assert
response.Should().NotBeNull();
}
这是我需要测试的实际方法
public class LibraryService : ILibraryService
{
private IRetryHttpRequest _retryHttpRequest;
public LibraryService(IRetryHttpRequest retryHttpRequest)
{
_retryHttpRequest = retryHttpRequest;
}
public async Task<ResponseModel> GetResponseForSearch(SearchRequest searchRequest, HttpClient client)
{
//send request and retry if failed
ResponseModel result = new ResponseModel();
HttpResponseMessage httpResponseMessage = await _retryHttpRequest.ExecuteAsync(() => new HttpRequestMessage(), client, 3);
//process response
if (httpResponseMessage != null)
{
string response = await httpResponseMessage.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<ResponseModel>(response);
}
return result;
}
}
public class RetryHttpRequest : IRetryHttpRequest
{
public async Task<HttpResponseMessage> ExecuteAsync(Func<HttpRequestMessage> requestMessage, HttpClient client, int maxTryValue)
{
var content = new StringContent("From Execute Async", Encoding.UTF8, "application/json");
var httpResponse = new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = content
};
return httpResponse;
}
}
当我单步执行代码时,对于下面这行代码,httpResponseMessage
变量返回 null
,尽管我已经在单元测试中用 200 响应模拟了它。
HttpResponseMessage httpResponseMessage = await _retryHttpRequest.ExecuteAsync(() => new HttpRequestMessage(), client, 3);
虽然问题似乎缺乏完整的解释,但以下内容用于演示目的,以展示如何使用最小起订量测试目标方法。
假设如下
public interface IRetryHttpRequest {
Task<HttpResponseMessage> ExecuteAsync(Func<HttpRequestMessage> requestMessage, HttpClient client, int maxTryValue);
}
public class LibraryService : ILibraryService {
private IRetryHttpRequest _retryHttpRequest;
public LibraryService(IRetryHttpRequest retryHttpRequest) {
_retryHttpRequest = retryHttpRequest;
}
public async Task<ResponseModel> GetResponseForSearch(SearchRequest searchRequest, HttpClient client) {
//send request and retry if failed
ResponseModel result = new ResponseModel();
HttpResponseMessage httpResponseMessage = await _retryHttpRequest.ExecuteAsync(() => new HttpRequestMessage(), client, 3);
//process response
if (httpResponseMessage != null) {
string response = await httpResponseMessage.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<ResponseModel>(response);
}
return result;
}
}
public interface ILibraryService {
}
请注意语法更改,这些更改会显示问题中显示的原始代码的错误。
以下测试演示了如何测试 LibraryService.GetResponse
方法并断言预期行为
public async Task SampleTest() {
//Arrange
var content = new StringContent("{}", Encoding.UTF8, "application/json");
var httpResponse = new HttpResponseMessage() {
StatusCode = HttpStatusCode.OK,
Content = content
};
var _mockRetryHttpRequest = new Mock<IRetryHttpRequest>();
_mockRetryHttpRequest
.Setup(_ => _.ExecuteAsync(It.IsAny<Func<HttpRequestMessage>>(), It.IsAny<HttpClient>(), It.IsAny<int>()))
.ReturnsAsync(httpResponse);
var lgService = new LibraryService(_mockRetryHttpRequest.Object);
//Act
var response = await lgService.GetResponseForSearch(new SearchRequest(), null);
//Assert
response.Should().NotBeNull();
}
FluentAssertions 用于断言预期行为。
一些注意事项
仅向被测对象提供了执行测试实际需要的依赖项。这意味着 mock
实际上不需要 被测方法也需要等待才能得到断言响应
因为我无权访问您的测试数据,所以我使用一个空的 JSON 对象“{}”来表示响应的内容以允许
JsonConvert
工作然后我建议您查看正在反序列化的测试数据。这可能是失败点,因为这是唯一可以将
result
设置为null
的地方,因为它是在函数顶部初始化的。
HttpClient
你不应该让你的测试方法异步。使其同步,然后执行以下操作而不是等待:
var task = lgService.GetResponseForSearch(new SearchRequest(), null);
task.Wait();
var response = task.Result;
response.Should().NotBeNull();