Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoFixture create property with internal setter

Is there some kind of way to let AutoFixture create properties with an internal setter?

I've looked at the AutoFixture source and found that in the AutoPropertiesCommand the GetProperties method checks whether a property has GetSetMethod() != null. With an internal setter this returns null, unless you set the ignorePublic argument to true.

The easiest thing would ofcourse be to make the setter public but in the project i'm working on this just wouldn't be the right solution.

Below is a simplified piece of code from the project as an example.

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);
    }
}
like image 671
Marco van Kimmenade Avatar asked Oct 13 '13 12:10

Marco van Kimmenade


1 Answers

Ideally, the tests shouldn't have to interact with the internal members of a class, since they are explicitly excluded from its public API. Instead, these members would be tested indirectly by the code paths initiated through the public API.

However, if this isn't feasible in your particular situation, a possible workaround could be to explicitly assign a value to the internal properties from within the tests.

You can do that in one of two ways:

  1. By exposing all internal members within the assembly to the test project using the InternalsVisibleTo attribute.
  2. By representing the modifiable state of the class in a specific interface and implement that explicitly.

In your example, option 1 would be:

// [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>();
    // ...
}

Option 2, instead, would be something like:

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>());
    // ...
}

Option 1 is fairly quick to implement, but has the side effect of opening up all internal members within the assembly, which may not be what you want.
Option 2, on the other hand, allows you to control what part of the object's state should be exposed as modifiable, while still keeping it separated the object's own public API.

As a side note, I'd like to point out that, since you're using xUnit, you can take advantage of AutoFixture's support for Data Theories to make your tests slightly more terse:

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

If you prefer to set the Name property to a known value while still keeping the rest of the Dummy object anonymous, you have also the possibility to combine the two within the same Data Theory:

[Theory, InlineAutoData("SomeName")]
public void Test(string name, Dummy dummy)
{
    ((IModifiableDummy)dummy).SetName(name);
    // ...
}
like image 119
Enrico Campidoglio Avatar answered Sep 19 '22 13:09

Enrico Campidoglio