Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

need to create convention for ApiControllers

Tags:

c#

autofixture

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

like image 438
cocogorilla Avatar asked Dec 20 '13 22:12

cocogorilla


People also ask

What is difference between controller and API controller?

The main difference is: Web API is a service for any client, any devices, and MVC Controller only serve its client. The same because it is MVC platform.

What is the purpose of API controller attribute?

The [ApiController] attribute applies inference rules for the default data sources of action parameters. These rules save you from having to identify binding sources manually by applying attributes to the action parameters.

How do API controllers work?

Web API Controller is similar to ASP.NET MVC controller. It handles incoming HTTP requests and send response back to the caller. Web API controller is a class which can be created under the Controllers folder or any other folder under your project's root folder.


1 Answers

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);
}
like image 84
Mark Seemann Avatar answered Nov 13 '22 16:11

Mark Seemann