简体   繁体   中英

Fill public property with private setter test data by AutoFixture

I want to test ConfirmDownloadInvoiceDate method. In addition, I want to create Order objects with my test data for ConfirmationDownloadInvoiceDate property by:

fixture.Create<Order>();

My Order class:

public class Order
{       
    public DateTime? ConfirmationDownloadInvoiceDate { get; private set; }

    public void ConfirmDownloadInvoiceDate(IDateTimeProvider timeProvider)
    {
        if (ConfirmationDownloadInvoiceDate == null)
        {
            ConfirmationDownloadInvoiceDate = timeProvider.Now();
        }
    }
}

Is it possible to fill that property with test data? I tried by create new class from ISpecimenBuilder but it seems it does not work.

By design, AutoFixture only fills out fields and properties when they're publicly writable, because that's what you can do as a client developer yourself, if you, instead of using AutoFixture, write the test data arrange phase by hand. In the above Order class, the ConfirmationDownloadInvoiceDate property doesn't have a public setter, so AutoFixture will ignore it.

The easiest workaround, obviously, is to make the setter public, but this is not always warranted.

In this particular case, you can customize creation of the Order class by telling AutoFixture that it should invoke the ConfirmDownloadInvoiceDate method when it creates Order objects.

One way to do that would be to first create a test-specific Stub implementation of IDateTimeProvider , for example like this:

public class StubDateTimeProvider : IDateTimeProvider
{
    public StubDateTimeProvider(DateTime value)
    {
        this.Value = value;
    }

    public DateTime Value { get; }

    public DateTime Now()
    {
        return this.Value;
    }
}

You could also use a dynamic mock library, like Moq, NSubstitute, or the like.

Use the stub to call the ConfirmDownloadInvoiceDate method, for example like this:

[Fact]
public void AutoFillConfirmationDownloadInvoiceDate()
{
    var fixture = new Fixture();
    fixture.Customize<Order>(c => c
        .Do(o => o.ConfirmDownloadInvoiceDate(fixture.Create<StubDateTimeProvider>())));

    var actual = fixture.Create<Order>();

    Assert.NotNull(actual.ConfirmationDownloadInvoiceDate);
    Assert.NotEqual(default(DateTime), actual.ConfirmationDownloadInvoiceDate);
}

This test passes. You should consider packaging the above customization in an ICustomization class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM