我们有几个.NET Core微服务/ API,我们希望进行一些集成测试。 因此,我们遵循了这些教程,除一种情况外,它都能正常工作。
想象一下,我有3个API,因此有3个“ TestServer”实例,每个实例都有自己的HttpClient来连接!
我展示了创建TestServer的方式:
private TestServer SetupAPI<TStartup>(string path, string uri) where TStartup : class
{
string rootPath = Path.Join(_rootPath, "path");
var hostBuilder = WebHost.CreateDefaultBuilder()
.UseUrls(uri)
.UseIISIntegration()
//.ConfigureServices(services => services.AddSecurityHeaders())
.UseContentRoot(rootPath)
.UseEnvironment("Development")
.ConfigureAppConfiguration(cb =>
{
cb.AddJsonFile("appsettings.json", optional: false)
//.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
})
.UseStartup<TStartup>();
TestServer server = new TestServer(hostBuilder);
server.BaseAddress = new Uri(uri);
return server;
}
我展示了如何创建HttpClient:
client = ArtistsServer.CreateClient();
client.BaseAddress = new Uri("http://localhost:5000");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
它运行良好,但是当我尝试以这种方式创建新的HttpClient时,它失败了: HttpClient httpClient =新的HttpClient(); httpClient.BaseAddress = new Uri(“ http://localhost:5000”);
真正的问题是某些微服务以这种方式创建自己的HttpClient以便与其他API通信!它们是通过appsettings.json文件设置的,并尝试连接到普通的真实HTTP服务器,而不是“ TestServer”服务器!
您有解决此问题的想法吗?
谢谢
答案 0 :(得分:0)
这不是这样的。集成测试是对组成单个应用程序的组件套件的测试。如果要测试Api1,则不会启动Api2和Api3的实例。您嘲笑那些,以便它们以已知且可预测的方式运行。如果您使用的是真实实例,甚至是 test 实例,那么即使Api1没问题,Api2的失败也可能导致您对Api1的测试失败。
因此,要使Api1与Api2通信,您需要一个HttpClient
来进行请求。 HttpClient
应该由IHttpClientFactory
提供,并注入注册为类型化客户端的服务类中。在此服务类上,您将添加与API调用相对应的方法。为了可测试,此服务类应实现一个接口,然后应在需要使用此API时注入该接口。大致如下:
public interface IApi2Service
{
Task<Foo> GetFooByIdAsync(int id);
}
public class Api2Service : IApi2Service
{
private readonly HttpClient _client;
public Api2Service(HttpClient client)
{
_client = client;
}
public async Task<Foo> GetFooByIdAsync(int id)
{
// use _client to make the API call
}
}
然后,在Startup.ConfigureServices
中:
services.AddHttpClient<IApi2Service, Api2Service>(c =>
{
c.BaseAddress = new Uri(Configuration["Api2BaseAddress"]);
});
最后,在需要与Api2进行交互的Api1中的类(可能是控制器)中,您可以执行以下操作:
public class SomeApi1Controller : ControllerBase
{
private readonly IApi2Service _api2Service;
public SomeApi1Controller(IApi2Service api2Service)
{
_api2Service = api2Service;
}
public async Task<IActionResult> SomeAction()
{
var foo = await _api2Service.GetFooByIdAsync(1);
}
}
现在,在正确设置代码之后,您只需将其嵌入Api2Service
的测试实现中,并存入GetFooByIdAsync
方法即可简单地返回测试Foo
实例,而不是实际上通过HttpClient
调用Api2。这样,您便确切知道将返回什么,并且可以适当地设计测试,并根据您要测试的内容返回不同类型的Foo
实例。