5

我正在尝试使用 AutoFixture 来简化我的生活。

我如何模拟一个班级

  • 非公共构造函数和
  • 非公开身份和
  • 静态“创建”方法?

例子

public class User
{
    private User(){}

    /// <summary>
    ///     Created by Database...
    /// </summary>
    public long? Id { get; protected set; }

    public string Name { get; protected set; }

    public static User Create(string name)
    {
        var user = new User {Name = name};
        return user;
    }
}

我尝试过使用 Factory 和 SpecimenBuilder 的组合:

    [Fact]
    public void CreatingUserWithId_Should_Work_UsingFactoryAndSpecimenBuilder()
    {
        IFixture fixture = new Fixture().Customize(new AutoFakeItEasyCustomization());
        fixture.Customizations.Add(new UserBuilder());
        fixture.Customize<User>(o => o.FromFactory(() => User.Create("foo")));

        var user = fixture.Create<User>();

        user.Should().NotBeNull();
        user.Id.Should().HaveValue();
    }

public class UserBuilder : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        var pi = request as PropertyInfo;
        if (pi == null) return new NoSpecimen(request);

        // The following code only works for public properties... :-(
        if (pi.Name == "Id" && pi.PropertyType == typeof (long?)) return 42;

        return new NoSpecimen(request);
    }
}

演示 C# 解决方案可在https://github.com/daptik/MockingStaticCreate获得

感谢任何指点,

帕特里克

4

1 回答 1

6

AF 将做正确的事情(User.Create()使用匿名名称 arg),无需任何自定义。

唯一缺少的一点是设置Id. 您必须自己回答哪个问题 - 您的消费代码首先应该如何做到这一点?当你决定了,你可以做fixture.Customize<User>( c => c.FromFactory( User.Create).Do( x => ???)

也许你可以考虑曝光一个演员也需要id。然后你可以做一个Customize<User>......GreedyConstructorQuery

如果您的 ORM 正在做一些古怪的反射并且您喜欢它和/或无法绕过它,您可以选择是否应该为您的测试:

a)也这样做 - 如果这与给定的测试或一组测试相关

b)认为这是可行的

关于将模拟和输入值混合到实体或值对象中 - 不要那样做(Mark Seemann 的命令与查询文章可能对您有所帮助)。您似乎需要/想要这样做的事实使您似乎在单个测试中过于雄心勃勃-您是否找到了最简单的测试方法并尝试以Assert最少的设置进行单个测试。

去购买GOOS 书吧——它会帮助你找出平衡这些权衡的方法。

于 2014-04-02T23:45:11.330 回答