need to create convention for ApiControllers
Asked Answered
T

1

11

I have a set of working imperative code in test and I'm trying to boil it down to an essential test convention.

My test looks like the following:

[Theory, BasicConventions]
public void GetVersionOnSiteVersionControllerReturnsASiteVersion(IFixture fixture)
{
    fixture.OmitAutoProperties = true;
    SiteVersion expected = fixture.Create<SiteVersion>();
    SiteVersion actual = null;

    var sut = fixture.Create<SiteVersionController>();

    var response = sut
        .GetSiteVersion()
        .ExecuteAsync(new CancellationToken())
        .Result
        .TryGetContentValue<SiteVersion>(out actual);

    actual.AsSource().OfLikeness<SiteVersion>().ShouldEqual(expected);
}

I also have a customization that allows this to work, namely by setting the HttpConfiguration and HttpRequestMessage to default non-null values.

public class ApiControllerCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        var origin = fixture.OmitAutoProperties;
        fixture.OmitAutoProperties = true;
        var sut = fixture.Create<SiteVersionController>();
        sut.Configuration = fixture.Create<HttpConfiguration>();
        sut.Request = fixture.Create<HttpRequestMessage>();
        fixture.Inject<SiteVersionController>(sut);
        fixture.OmitAutoProperties = origin;
    }
}

First, this looks ugly, but if I use Build<>().omit().with(config).with(request), it shuts off the automoq customization which it needs to build those instances.

Second, this only works for a SiteVersionController. I'd much rather generalize this for all my ApiControllers (maybe that's a bad idea, but I won't know until I try).

Essentially my convention would be as follows: for all ApiControllers, create them without auto properties but do set the http configuration and request message properties to default non-null values

Threonine answered 20/12, 2013 at 22:7 Comment(3)
What ApiController type are you working with? ASP.NET Web API? Which version?Gustin
My NuGet package manager says ASP.NET Web API Version 5.0.0Threonine
Related: https://mcmap.net/q/475280/-automocking-web-api-2-controller/126014Gustin
G
10

ApiControllers are quite difficult to wire up, because you'll need to assign certain properties to them in order for everything to work. At the very least, you'll need the Request property to be assigned, because otherwise, the Controller can't invoke Request.CreateResponse. Thus, switching off auto-properties for ApiController instances isn't a good strategy. Instead, you can configure AutoFixture to wire up HttpRequestMessage instances correctly.

Web API 1

With ASP.NET Web API 1, I usually use a Customization like this:

public class WebApiCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<HttpRequestMessage>(c => c
            .Do(x =>
                x.Properties.Add(
                    HttpPropertyKeys.HttpConfigurationKey,
                    new HttpConfiguration())));
    }
}

Since auto-properties are on by default, this is going to assign an appropriate instance of HttpRequestMessage to ApiController.Request. Together with an Auto-mocking Customization, Fixture can now create instances of all your ApiController classes.

Web API 2

With ASP.NET Web API 2 (5.0.0.0), things are a little more complicated, but with a bit of trial and error, I got this Customization to pass 808 tests:

public class WebApiCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<HttpConfiguration>(c => c
            .OmitAutoProperties());
        fixture.Customize<HttpRequestMessage>(c => c
            .Do(x =>
                x.Properties.Add(
                    HttpPropertyKeys.HttpConfigurationKey,
                    fixture.Create<HttpConfiguration>())));
        fixture.Customize<HttpRequestContext>(c => c
            .Without(x => x.ClientCertificate));
    }
}

Conventions

If you package that into an [AutoData] attribute, you should be able to refactor your test to:

[Theory, BasicConventions]
public void GetVersionOnSiteVersionControllerReturnsASiteVersion(
    SiteVersionController sut,
    SiteVersion expected)
{
    SiteVersion actual = null;

    var response = sut
        .GetSiteVersion()
        .ExecuteAsync(new CancellationToken())
        .Result
        .TryGetContentValue<SiteVersion>(out actual);

    actual.AsSource().OfLikeness<SiteVersion>().ShouldEqual(expected);
}
Gustin answered 21/12, 2013 at 20:55 Comment(3)
this is great. Question, thankfully, I'm getting the hang of AutoFixture, most of my hangups are trying to wire things like this. How do you go about researching this, a strategy? or just experience?Threonine
Well, personally, I wrote AutoFixture, so you could say I'm cheating :) I invite others to answer this question, too.Gustin
The same customization for ASP.NET Web API 2 in F# can be found at: gist.github.com/moodmosaic/2789ba06980880217df7Robinson

© 2022 - 2024 — McMap. All rights reserved.