Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automocking Web Api 2 controller

I am trying to auto mock ApiController class in my test cases. It worked perfectly when I was using WebApi1. I started to use WebApi2 on the new project and I am getting this exception thrown after I try to run my new tests:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Security.Cryptography.CryptographicException: pCertContext is an invalid handle.
   at System.Security.Cryptography.CAPI.CertSetCertificateContextProperty(SafeCertContextHandle pCertContext, UInt32 dwPropId, UInt32 dwFlags, SafeLocalAllocHandle safeLocalAllocHandle)
   at System.Security.Cryptography.X509Certificates.X509Certificate2.set_Archived(Boolean value)

My test code:

[Theory, AutoMoqData]
public void approparte_status_code_is_returned(
    string privateKey,
    UsersController sut)
{
    var response = sut.GetUser(privateKey);
    var result = response;

    Assert.Equal(HttpStatusCode.OK, result.StatusCode);
}

Test case does work if I create sut manually:

[Theory, AutoMoqData]
public void approparte_status_code_is_returned(
    string privateKey,
    [Frozen]Mock<IUserModel> stubModel)
{
    var sut = new UsersController(stubModel.Object);
    var response = sut.GetUser(privateKey);
    var result = response;

    Assert.Equal(HttpStatusCode.OK, result.StatusCode);
}

It's seems that something goes wrong when trying to mock the ControllerContext.RequestContext.ClientCertificate I've tried to create a fixture without it (using AutoFixture .Without() method) but then even the old tests started to fail.

My AutoMoqDataAttribute:

public class AutoMoqDataAttribute : AutoDataAttribute
{
    public AutoMoqDataAttribute()
        : base(new Fixture()
            .Customize(new WebApiCustomization()))
    {
    }
}

WebApi customization:

public class WebApiCustomization : CompositeCustomization
{
    public WebApiCustomization() 
        : base(
        new HttpRequestMessageCustomization(),
        new AutoMoqCustomization())
    {
    }
}

HttpRequestMessage customization:

public class HttpRequestMessageCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<HttpRequestMessage>(c => c
            .Without(x => x.Content)
            .Do(x =>
            {
                x.Properties[HttpPropertyKeys.HttpConfigurationKey] = new HttpConfiguration();
            })
            );
    }
}

UsersController:

/// <summary>
/// Handles user's account. 
/// </summary>
[RoutePrefix("api/v1/users/{privateKey:length(64)}")]
public class UsersController : ApiController
{
    private readonly IUserModel _model;

    public UsersController(IUserModel model)
    {
        _model = model;
    }

    /// <summary>
    /// Returns a user.
    /// </summary>
    /// <param name="privateKey">The private key of the user.</param>
    /// <returns>
    /// 200 (OK) with user data is returned when user is found.
    /// 404 (Not found) is returned when user is not found.
    /// </returns>
    [HttpGet]
    [Route("")]
    public HttpResponseMessage GetUser(string privateKey)
    {
        UserProjection projection;

        try
        {
            projection = new UserProjection(_model.Get(privateKey));
        }
        catch (UserNotFoundException)
        {
            return new HttpResponseMessage(HttpStatusCode.NotFound);
        }

        return Request.CreateResponse(HttpStatusCode.OK, projection);
    }
}
like image 851
user2910739 Avatar asked Nov 11 '13 14:11

user2910739


People also ask

How to create a web API controller?

Web API controller is a class which can be created under the Controllers folder or any other folder under your project's root folder. The name of a controller class must end with "Controller" and it must be derived from System.Web.Http. ApiController class.

What is the API auto mocking integration?

The API Auto Mocking integration creates and maintains a semi-static mock of your API based on the responses and examples defined in your OpenAPI 3.0 or 2.0 definition. The mock is updated every time you save your API.

How do I use API auto mocking with SwaggerHub?

Select API Auto Mocking from the list of integrations. Specify the mock server parameters (see below ). Click Save and Execute, then Done. The mock is now ready to use. Or if you use the Update host setting option, you can call the mock API directly from the interactive API docs on SwaggerHub: Click the image to enlarge it.

How to name action methods in the web API controller?

As mentioned above, name of the action methods in the Web API controller plays an important role. Action method name can be the same as HTTP verbs like Get, Post, Put, Patch or Delete as shown in the Web API Controller example above.


2 Answers

Note: Assuming that the UserController class takes an IUserModel through its constructor.

As it looks like, the default constructor of ApiController performs some work (probably more than simple assignments).

If the UserController class takes an IUserModel through its constructor, you can pick that constructor (the greediest) instead.

Update:

Replace the HttpRequestMessageCustomization customization with:

internal class ApiControllerCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<HttpRequestMessage>(c => c
            .Without(x => x.Content)
            .Do(x => x.Properties[HttpPropertyKeys.HttpConfigurationKey] =
                new HttpConfiguration()));

        fixture.Customize<UsersController>(c => c
            .OmitAutoProperties()
            .With(x => x.Request, fixture.Create<HttpRequestMessage>()));
    }
}

And the original test will execute fine.

like image 119
Nikos Baxevanis Avatar answered Oct 22 '22 14:10

Nikos Baxevanis


Based on Nikos' answer:

This is a more generic way of using this customization where the controller type can be supplied and the Customization can be used for any controller

internal class WebApiCustomization<TControllerType> : ICustomization
    where TControllerType : ApiController
    {
        public void Customize(IFixture fixture)
        {
            fixture.Customize<HttpRequestMessage>(c => c
                .Without(x => x.Content)
                .Do(x => x.Properties[HttpPropertyKeys.HttpConfigurationKey] =
                    new HttpConfiguration()));

            fixture.Customize<TControllerType>(c => c
                .OmitAutoProperties()
                .With(x => x.Request, fixture.Create<HttpRequestMessage>()));
}
}

Then use as follows:

var fixture = new Fixture().Customize(
    new WebApiCustomization<UsersController>());
var sut = fixture.Create<UsersController>();
like image 2
Aage Avatar answered Oct 22 '22 14:10

Aage