例如,我有一个与HttpClient
public class DomainActions : IDomainActions
{
private readonly HttpClient _client;
private readonly IConfiguration _configuration;
public DomainActions(IConfiguration configuration)
{
_configuration = configuration;
_client = new HttpClient()
{
BaseAddress = new Uri(_configuration.GetSection("DomainRegistration:BaseAddress").Value)
};
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _configuration.GetSection("DomainRegistration:Token").Value);
}
public async Task<List<DomainDto>> GetDomainListAsync()
{
var responseMessage = await _client.GetAsync("domains");
return await ProcessingDomainListResponseAsync(responseMessage);
}
然后我们通过以下方式解决该问题:
services.AddTransient<IConfiguration>(....);
services.AddTransient<IDomainActions, DomainActions>();
和客户类别:
public class AddMxRecordToRegistrator
{
protected readonly IDomainActions domainActions;
public AddMxRecordToRegistrator(IDomainActions domainActions )
{
this.domainActions = domainActions ;
}
public async Task CreateDomainRecordAsync()
{
await domainActions.CreateDomainRecordAsync(queueItem.DomainForRegistration.DomainName, new DomainRegistrationCore.Models.DomainRecordDto
{
Content = queueItem.MxRecord,
Name = String.Empty,
Priority = 0,
Ttl = 3600,
Type = DomainRecordType.MX.ToString(),
Regions = null
});
好的,它工作正常。
现在,我想为AddMxRecordToRegistrator类创建单元测试,但是我不想使用真正的httpClient。怎么做?当然,我可以再添加一个依赖项:
public class DomainActions : IDomainActions
{
private readonly HttpClient _client;
private readonly IConfiguration _configuration;
public DomainActions(IConfiguration configuration, HttpMessageHandler httpMessageHandler)
{
_configuration = configuration;
_client = new HttpClient(httpMessageHandler)
{
BaseAddress = new Uri(_configuration.GetSection("DomainRegistration:BaseAddress").Value)
};
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _configuration.GetSection("DomainRegistration:Token").Value);
}
public DomainActions(IConfiguration configuration) : this(configuration, new HttpClientHandler())
{
}
public async Task<List<DomainDto>> GetDomainListAsync()
{
var responseMessage = await _client.GetAsync("domains");
return await ProcessingDomainListResponseAsync(responseMessage);
}
然后修改DI组成根:
services.AddTransient<IConfiguration>(....);
services.AddTransient<HttpMessageHandler>(....);
services.AddTransient<IDomainActions, DomainActions>();
但是,为什么客户部分(在我们的情况下是组合根目录)仅因为需要创建单元测试而对DomainActions
的内部细节一无所知?就像我们违反了单元测试的封装一样。如何正确实施?
答案 0 :(得分:3)
要扩展@CamiloTerevinto的评论,c
应该通过依赖注入依赖于c - '0'
,即该接口应该是传递给其构造函数的参数。
从封装的角度来看,AddMxRecordToRegistrator
不应该知道IDomainActions
依赖于AddMxRecordToRegistrator
或DomainActions
。甚至不应该知道IConfiguration
存在,因为那是一个具体的类,而HttpMessageHandler
应该依赖于接口,而不是具体的类。
答案 1 :(得分:0)
但是为什么客户部分(在我们的情况下是组合根)应该知道 关于DomainActions内部细节的任何事情,仅仅是因为我们需要 创建单元测试?
组合根仅位于会“知道”所有较低级别依赖项的应用程序中。
“ Composition”根目录的作用是通过运行时实现组合所需的类。
类AddMxRecordToRegistrator
显然取决于抽象IDomainActions
,因此对于单元测试AddMxRecordToRegistrator
,您只需传递伪造的IDomainActions
。