AutoFixture 自动设置 return 任务类型 <IEnumerable<>> 自定义
AutoFixture auto setup return type of Task<IEnumerable<>> customization
我在测试中将 AutoFixture 与 AutoMoqCustomization 结合使用。
我有一个服务是被测系统的依赖项:
ISomeService
{
Task<IEnumerable<int>> Get();
}
我在被测系统内部调用:
var collection = await _someService.Get(); // collection is empty
我不关心集合中的内容,但我需要集合 而不是 为空。我是这样做的:
_fixture.Freeze<Mock<ISomeService>>()
.Setup(service => service.Get())
.Returns(Task.FromResult(_fixture.CreateMany<int>()));
看起来应该通过自定义来完成。我创建并注册了一个:
public class TaskCollectionCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(
new FilteringSpecimenBuilder(
new TaskCollectionBuilder(),
new GenericTypeSpecification(typeof(Task<>))));
}
private class TaskCollectionBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
// never enters here
}
}
}
问题是它的 Create 方法从未被输入。有任何想法或现成的解决方案吗?
编辑
添加 GenericTypeSpecification 来源
public class GenericTypeSpecification : IRequestSpecification
{
private readonly Type _type;
public GenericTypeSpecification(Type type)
{
_type = type;
}
public bool IsSatisfiedBy(object request)
{
var requestedType = request as Type;
return requestedType != null &&
requestedType.IsGenericType &&
requestedType.GetGenericTypeDefinition() == _type;
}
}
AutoFixture 已经支持开箱即用的任务,这一点证明了这一点 Characterization Test:
[Fact]
public void AutoFixtureAlreadySupportsTasks()
{
var fixture = new Fixture();
var t = fixture.Create<Task<IEnumerable<int>>>();
Assert.NotEmpty(t.Result);
}
因此,您只需配置 Test Double 服务,如下所示:
[Fact]
public void ConfigureMock()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
fixture.Freeze<Mock<ISomeService>>()
.Setup(s => s.Get())
.Returns(fixture.Create<Task<IEnumerable<int>>>());
var svc = fixture.Create<ISomeService>();
Assert.NotEmpty(svc.Get().Result);
}
如果您认为这工作量太大,您也可以让 AutoConfiguredMoqCustomization
代劳,如下所示:
[Fact]
public void SimplestCustomization()
{
var fixture =
new Fixture().Customize(new AutoConfiguredMoqCustomization());
var svc = fixture.Create<ISomeService>();
Assert.NotEmpty(svc.Get().Result);
}
但是,就我个人而言,我不是自动配置的测试替身的忠实拥护者,因为我认为 explicit is better than implicit, and Test Double configuration ought to be an explicit part of a unit test, because it describes the Indirect Input 用于测试用例。
我在测试中将 AutoFixture 与 AutoMoqCustomization 结合使用。
我有一个服务是被测系统的依赖项:
ISomeService
{
Task<IEnumerable<int>> Get();
}
我在被测系统内部调用:
var collection = await _someService.Get(); // collection is empty
我不关心集合中的内容,但我需要集合 而不是 为空。我是这样做的:
_fixture.Freeze<Mock<ISomeService>>()
.Setup(service => service.Get())
.Returns(Task.FromResult(_fixture.CreateMany<int>()));
看起来应该通过自定义来完成。我创建并注册了一个:
public class TaskCollectionCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(
new FilteringSpecimenBuilder(
new TaskCollectionBuilder(),
new GenericTypeSpecification(typeof(Task<>))));
}
private class TaskCollectionBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
// never enters here
}
}
}
问题是它的 Create 方法从未被输入。有任何想法或现成的解决方案吗?
编辑
添加 GenericTypeSpecification 来源
public class GenericTypeSpecification : IRequestSpecification
{
private readonly Type _type;
public GenericTypeSpecification(Type type)
{
_type = type;
}
public bool IsSatisfiedBy(object request)
{
var requestedType = request as Type;
return requestedType != null &&
requestedType.IsGenericType &&
requestedType.GetGenericTypeDefinition() == _type;
}
}
AutoFixture 已经支持开箱即用的任务,这一点证明了这一点 Characterization Test:
[Fact]
public void AutoFixtureAlreadySupportsTasks()
{
var fixture = new Fixture();
var t = fixture.Create<Task<IEnumerable<int>>>();
Assert.NotEmpty(t.Result);
}
因此,您只需配置 Test Double 服务,如下所示:
[Fact]
public void ConfigureMock()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
fixture.Freeze<Mock<ISomeService>>()
.Setup(s => s.Get())
.Returns(fixture.Create<Task<IEnumerable<int>>>());
var svc = fixture.Create<ISomeService>();
Assert.NotEmpty(svc.Get().Result);
}
如果您认为这工作量太大,您也可以让 AutoConfiguredMoqCustomization
代劳,如下所示:
[Fact]
public void SimplestCustomization()
{
var fixture =
new Fixture().Customize(new AutoConfiguredMoqCustomization());
var svc = fixture.Create<ISomeService>();
Assert.NotEmpty(svc.Get().Result);
}
但是,就我个人而言,我不是自动配置的测试替身的忠实拥护者,因为我认为 explicit is better than implicit, and Test Double configuration ought to be an explicit part of a unit test, because it describes the Indirect Input 用于测试用例。