【问题标题】:AutoFixture auto setup return type of Task<IEnumerable<>> customizationAutoFixture 自动设置返回类型的 Task<IEnumerable<>> 自定义
【发布时间】:2015-03-05 11:32:26
【问题描述】:

我在测试中使用 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;
    }
}

【问题讨论】:

  • 什么是GenericTypeSpecification
  • @MarkSeemann 抱歉,我以为它是库的一部分,但事实证明肯定是另一个团队成员创建了它。请查看编辑。
  • 还没有看到任何修改...
  • @MarkSeemann 忘记点击“保存编辑”。

标签: c# unit-testing autofixture


【解决方案1】:

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,并且测试替身配置应该是单元测试的明确部分,因为它描述了@987654324 @ 用于测试用例。

【讨论】:

  • 谢谢。 AutoConfiguredMoqCustomization 确实有效。附带说明一下,如果同时注册了 AutoConfiguredMoqCustomization 和 AutoMoqCustomization 自定义,则它不会自动配置模拟。不知道是bug还是设计。 :)
  • 可能是by design,但我不能说更多,因为我不知道有任何细节。
  • @gisek 只会触发两种自定义中的一种,这取决于您首先应用哪一种。由于AutoConfiguredMoqCustomizationAutoMoqCustomization 的超集,因此无需同时使用两者。作为旁注,您也可以使用.ReturnsUsingFixture(fixture) 而不是.Returns(fixture.Create&lt;Task&lt;IEnumerable&lt;int&gt;&gt;&gt;())
  • @dcastro 谢谢!我不知道 ReturnsUsingFixture 方法。看起来很有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-10
  • 1970-01-01
相关资源
最近更新 更多