AutoFixture使用内部setter创建属性

时间:2013-10-13 12:45:49

标签: c# .net unit-testing autofixture

是否有某种方法让AutoFixture使用内部setter创建属性?

我查看了AutoFixture源代码,发现在AutoPropertiesCommand中,GetProperties方法检查属性是否具有GetSetMethod()!= null。 除非将ignorePublic参数设置为true,否则使用内部setter将返回null。

最简单的事情就是让公司成员公开,但在项目中,我正在努力解决这个问题,这不是正确的解决方案。

以下是项目中的一段简化代码。

public class Dummy
{
    public int Id { get; set; }
    public string Name { get; internal set; }
}

public class TestClass
{
    [Fact]
    public void Test()
    {
        var dummy = new Fixture().Create<Dummy>();
        Assert.NotNull(dummy.Name);
    }
}

1 个答案:

答案 0 :(得分:4)

理想情况下,测试不应该与类的internal成员进行交互,因为它们是从其公共API中明确排除的。相反,这些成员将通过公共API启动的代码路径间接进行测试。

但是,如果在您的特定情况下这不可行,则可能的解决方法是从测试中明确地将值分配给内部属性。

您可以通过以下两种方式之一来实现:

  1. 使用InternalsVisibleTo属性将程序集中的所有内部成员公开给测试项目。
  2. 通过在特定接口中表示类的可修改状态并明确实现它。
  3. 在您的示例中,选项1将是:

    // [assembly:InternalsVisibleTo("Tests")]
    // is applied to the assembly that contains the 'Dummy' type
    
    [Fact]
    public void Test()
    {
        var fixture = new Fixture();
        var dummy = fixture.Create<Dummy>();
        dummy.Name = fixture.Create<string>();
        // ...
    }
    

    选项2,取而代之的是:

    public class Dummy : IModifiableDummy
    {
        public string Name { get; private set; }
    
        public void IModifiableDummy.SetName(string value)
        {
            this.Name = value;
        }
    }
    
    [Fact]
    public void Test()
    {
        var fixture = new Fixture();
        var dummy = fixture.Create<Dummy>();
        ((IModifiableDummy)dummy).SetName(fixture.Create<string>());
        // ...
    }
    

    选项1的实施起来相当快,但是在装配体中打开所有内部成员的副作用可能不是您想要的。
    另一方面,选项2允许您控制对象状态的哪些部分应该被公开为可修改,同时仍然将它与对象自己的公共API分开。

    作为旁注,我想指出,因为你正在使用xUnit,你可以利用AutoFixture的support for Data Theories来让你的测试更加简洁:

    [Theory, AutoData]
    public void Test(Dummy dummy, string name)
    {
        ((IModifiableDummy)dummy).SetName(name);
        // ...
    }
    

    如果您希望将Name属性设置为已知值,同时仍保持Dummy对象的其余部分匿名,则还可以{{3在相同的数据理论中:

    [Theory, InlineAutoData("SomeName")]
    public void Test(string name, Dummy dummy)
    {
        ((IModifiableDummy)dummy).SetName(name);
        // ...
    }