Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Let AutoFixture create DateTime in UTC?

Tags:

autofixture

By default AutoFixture creates DateTime structs in "local, unspecified time".

I have been trying to find a way to configure it to create DateTime structs with UTC kind, but so far unsuccessful.

Is there a way to do this?

like image 216
Jesper Lund Stocholm Avatar asked Mar 27 '14 11:03

Jesper Lund Stocholm


1 Answers

Preamble

AutoFixture was originally build as a tool for Test-Driven Development (TDD), and TDD is all about feedback. In the spirit of GOOS, you should listen to your tests. If the tests are hard to write, you should consider your API design. AutoFixture tends to amplify that sort of feedback, so my first reaction is to challenge your motivation for wanting to do this.

Is DateTime the right type?

If it really matters that DateTime values are in UTC, then perhaps System.DateTime isn't the best data type for the job. Perhaps DateTimeOffset would be a better option?

AutoFixture will happily create DateTimeOffset values for you.

Can you change the value after it's generated?

If you're using AutoFixture to create the primitive values themselves, you could also just convert them after you get them from AutoFixture:

var dt = fixture.Create<DateTime>().ToUniversalTime();

If you really must change AutoFixture's behaviour

However, if you don't control the API you're testing, and those DateTime values are deeply nested in some data structure, you'll need to configure AutoFixture to build DateTime values in UTC.

Here's one way to do it:

public class UtcConverter : ISpecimenBuilder
{
    private readonly ISpecimenBuilder builder;

    public UtcConverter(ISpecimenBuilder builder)
    {
        this.builder = builder;
    }

    public object Create(object request, ISpecimenContext context)
    {
        var t = request as Type;

        // Abort if request not valid for this type
        if (t == null || t != typeof(DateTime))
            return new NoSpecimen(request);

        var specimen = this.builder.Create(request, context);
        if (!(specimen is DateTime))
            return new NoSpecimen(request);
        return ((DateTime)specimen).ToUniversalTime();
    }
}

You can use it like demonstrated by this passing test:

[Fact]
public void ResolveUtcDate()
{
    var fixture = new Fixture();
    fixture.Customizations.Add(
        new UtcConverter(
            new RandomDateTimeSequenceGenerator()));
    var dt = fixture.Create<DateTime>();
    Assert.Equal(DateTimeKind.Utc, dt.Kind);
}
like image 52
Mark Seemann Avatar answered Oct 11 '22 09:10

Mark Seemann