我试图在我的项目(带有.net core 2.1的c#)中构建通用HTTP服务,并且已经按照下面的代码段HttpService
进行了构建。
我还开始通过从我的业务逻辑类中调用它来开始使用它,该逻辑类使用此通用PostAsync
方法将HTTP调用发布到正文中包含内容的第三者。效果很好。
但是,当我尝试对其进行测试时,我失败了!
实际上,当我尝试调试(测试模式)时,即使使用伪造的对象和模拟,调试器到达业务类null
中的这一行var result = await _httpService.PostAsync("https://test.com/api", content);
时,我也会收到Processor
响应,尽管它在调试模式,无需测试/模拟。
HTTP服务:
public interface IHttpService
{
Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content);
}
public class HttpService : IHttpService
{
private readonly IHttpClientFactory _httpClientFactory;
public HttpService(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<HttpResponseMessage> PostAsync(string requestUri, HttpContent content)
{
var httpClient = _httpClientFactory.CreateClient();
httpClient.Timeout = TimeSpan.FromSeconds(3);
var response = await httpClient.PostAsync(requestUri, content).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return response;
}
}
商务舱:
public class Processor : IProcessor
{
private readonly IHttpService _httpService;
public Processor() { }
public Processor(IHttpService httpService, IAppSettings appSettings)
{
_httpService = httpService;
}
public async Task<HttpResponseMessage> PostToVendor(Order order)
{
// Building content
var json = JsonConvert.SerializeObject(order, Formatting.Indented);
var content = new StringContent(json, Encoding.UTF8, "application/json");
// HTTP POST
var result = await _httpService.PostAsync("https://test.com/api", content); // returns null during the test without stepping into the method PostAsyn itself
return result;
}
}
测试课程:
public class MyTests
{
private readonly Mock<IHttpService> _fakeHttpMessageHandler;
private readonly IProcessor _processor; // contains business logic
private readonly Fixture _fixture = new Fixture();
public FunctionTest()
{
_fakeHttpMessageHandler = new Mock<IHttpService>();
_processor = new Processor(_fakeHttpMessageHandler.Object);
}
[Fact]
public async Task Post_To_Vendor_Should_Return_Valid_Response()
{
var fakeHttpResponseMessage = new Mock<HttpResponseMessage>(MockBehavior.Loose, new object[] { HttpStatusCode.OK });
var responseModel = new ResponseModel
{
success = true,
uuid = Guid.NewGuid().ToString()
};
fakeHttpResponseMessage.Object.Content = new StringContent(JsonConvert.SerializeObject(responseModel), Encoding.UTF8, "application/json");
var fakeContent = _fixture.Build<DTO>().Create(); // DTO is the body which gonna be sent to the API
var content = new StringContent(JsonConvert.SerializeObject(fakeContent), Encoding.UTF8, "application/json");
_fakeHttpMessageHandler.Setup(x => x.PostAsync(It.IsAny<string>(), content))
.Returns(Task.FromResult(fakeHttpResponseMessage.Object));
var res = _processor.PostToVendor(fakeContent).Result;
Assert.NotNull(res.Content);
var actual = JsonConvert.SerializeObject(responseModel);
var expected = await res.Content.ReadAsStringAsync();
Assert.Equal(expected, actual);
}
}
答案 0 :(得分:3)
您的问题出在模拟设置中
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class Post {
final List<dynamic> data;
Post({this.data});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
data: json['response'],
);
}
}
class LoaderPublicity extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _LoaderPublicity();
}
}
class _LoaderPublicity extends State<LoaderPublicity> {
List allPublicity;
@override
void initState() {
super.initState();
getPublicity().then((value) {
print(allPublicity);
});
print(allPublicity);
}
//Obtener todas las publicidades desde el api
Future<void> getPublicity() async {
var response = await http.post(
'http://contablenift.co:3008/consult/getGeneralPublicity',
body: {'actividad': "Turistico", 'location': "No"});
print('????????2');
if (response.statusCode == 200) {
setState(() {
allPublicity = Post.fromJson(json.decode(response.body)).data;
});
}
}
@override
Widget build(BuildContext context) {
getPublicity();
// TODO: implement build
return Container(
child: Column(
children: <Widget>[Text('Aqui va la publicidad')],
),
);
}
}
PostAsync方法的第二个参数应该为_fakeHttpMessageHandler.Setup(x => x.PostAsync(It.IsAny<string>(), content))
.Returns(Task.FromResult(fakeHttpResponseMessage.Object));
,但是由于StringContent是引用类型,因此您在模拟中设置的content
与您在处理器中创建的content
不同。如果将其更改为下一个,它将按预期工作:
content
P.S。对PostAsync的响应为null表示该方法具有默认设置,这意味着它将返回默认值