Automocking网页API 2控制器 [英] Automocking Web Api 2 controller

查看:310
本文介绍了Automocking网页API 2控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图自动模拟ApiController类在我的测试案例。它完美地工作,当我使用WebApi1。我开始使用WebApi2上新的项目,我得到这个异常抛出后,我尝试运行我的新测试:

 系统.Reflection.TargetInvocationException:异常已被调用的目标引发异常。 ---> System.Security.Cryptography.CryptographicException:pCertContext是无效的句柄。在System.Security.Cryptography.CAPI.CertSetCertificateContextProperty(SafeCertContextHandle pCertContext,UInt32的dwPropId,UInt32的dwFlags中,SafeLocalAllocHandle safeLocalAllocHandle)
。在System.Security.Cryptography.X509Certificates.X509Certificate2.set_Archived
(布尔值)

我的测试代码:

  [理论AutoMoqData] 
公共无效approparte_status_code_is_returned(
串privateKey,
UsersController SUT)
{
VAR响应= sut.GetUser(privateKey);
VAR的结果=响应;

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



测试情况下不工作,如果我创建SUT手动:

  [理论AutoMoqData] 
公共无效approparte_status_code_is_returned(
串privateKey,
[冰冻]模拟< IUserModel> stubModel )
{
变种SUT =新UsersController(stubModel.Object);
VAR响应= sut.GetUser(privateKey);
VAR的结果=响应;

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



这似乎试图嘲笑ControllerContext.RequestContext.ClientCertificate时出错我想尽量创造没有它夹具(使用AutoFixture。没有()方法),但是即使是旧的测试启动失败



我AutoMoqDataAttribute:

 公共类AutoMoqDataAttribute:AutoDataAttribute 
{
公共AutoMoqDataAttribute()
:基地(新灯()
.Customize(新WebApiCustomization()))
{
}
}

的WebAPI定制:

 公共类WebApiCustomization:CompositeCustomization 
{
公共WebApiCustomization ()
:基地(
新HttpRequestMessageCustomization(),
新AutoMoqCustomization())
{
}
}

HttpRequestMessage定制:

 公共类HttpRequestMessageCustomization:ICustomization 
{
公共无效自定义(IFixture夹具)
{
fixture.Customize< HttpRequestMessage>(C => ç
。没有(X => x.Content)
。做(X =>
{
x.Properties [HttpPropertyKeys.HttpConfigurationKey] =新HttpConfiguration();
})
);
}
}



UsersController:

  ///<总结> 
///处理用户的帐户。
///< /总结>
[RoutePrefix(API / V1 /用户/ {privateKey:长度(64)})]
公共类UsersController:ApiController
{
私人只读IUserModel _model;

公共UsersController(IUserModel模型)
{
_model =模型;
}

///<总结>
///返回用户。
///< /总结>
///&下; PARAM NAME =privateKey>本用户的私有密钥下; /参数>
///<退货和GT;
/// 200(OK)用户数据时发现用户被返回。
/// 404(未找到)当找不到用户返回。
///< /回报>
[HTTPGET]
[路线()]
公共HttpResponseMessage的getUser(字符串privateKey)
{
UserProjection投影;


{
投影=新UserProjection(_model.Get(privateKey));
}
赶上(UserNotFoundException)
{
返回新HttpResponseMessage(HttpStatusCode.NotFound);
}

返回Request.CreateResponse(HttpStatusCode.OK,投影);
}
}


解决方案

注意
回答需要的相同的定制要复制为每个新ApiController。



广义的办法



这是另一种方式是自动填写请求所有ApiControllers(从而节省您剪下)属性:

 内部类ApiControllerCustomization:ICustomization 
{
公共无效自定义(IFixture夹具)
{
fixture.Customizations.Add(
新FilteringSpecimenBuilder(
新的后处理(
新MethodInvoker(
新ModestConstructorQuery()),
新ApiControllerFiller()),
新ApiControllerSpecification()));
}

私有类ApiControllerFiller:ISpecimenCommand
{
公共无效执行(对象样本,ISpecimenContext上下文)
{
如果(样本= = NULL)
抛出新的ArgumentNullException(标本);
如果(上下文== NULL)
抛出新的ArgumentNullException(上下文);

VAR的目标=样品为ApiController;
如果(目标== NULL)
抛出新的ArgumentException(
的检体必须是ApiController的一个实例。,
样品);

target.Request =
(HttpRequestMessage)context.Resolve(
typeof运算(HttpRequestMessage));
}
}

私有类ApiControllerSpecification:IRequestSpecification
{
公共BOOL IsSatisfiedBy(对象请求)
{
变种的RequestType =请求的类型;
如果(的RequestType == NULL)
返回false;
返回的typeof(ApiController).IsAssignableFrom(请求类型);
}
}
}



类型的值 HttpRequestMessage ,为请求属性,使用以下的自定义建:

 内部类HttpRequestMessageCustomization:ICustomization 
{
公共无效自定义(IFixture夹具)
{
fixture.Customize< HttpRequestMessage>(三=以及c
。没有(X => x.Content)
。做(X => x.Properties [HttpPropertyKeys.HttpConfigurationKey] =
新HttpConfiguration()));
}
}



包装一切都变成复合定制



创建一个定制的复合如下 - 注意的 AutoFixture自定义的顺序事

 内部类ApiControllerConventions:CompositeCustomization 
{
内部ApiControllerConventions()
:基地(
新HttpRequestMessageCustomization(),
新ApiControllerCustomization(),
新AutoMoqCustomization())
{
}
}

希望有所帮助。


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);
    }
}

解决方案

Note: The original answer requires the same customization to be copied for each new ApiController.

Generalized approach

An alternative way is to automatically fill the Request property on all ApiControllers (thus saving you from cut, copy, and paste):

internal class ApiControllerCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Add(
            new FilteringSpecimenBuilder(
                new Postprocessor(
                    new MethodInvoker(
                        new ModestConstructorQuery()),
                    new ApiControllerFiller()),
                new ApiControllerSpecification()));
    }

    private class ApiControllerFiller : ISpecimenCommand
    {
        public void Execute(object specimen, ISpecimenContext context)
        {
            if (specimen == null)
                throw new ArgumentNullException("specimen");
            if (context == null)
                throw new ArgumentNullException("context");

            var target = specimen as ApiController;
            if (target == null)
                throw new ArgumentException(
                    "The specimen must be an instance of ApiController.", 
                    "specimen");

            target.Request =
                (HttpRequestMessage)context.Resolve(
                    typeof(HttpRequestMessage));
        }
    }

    private class ApiControllerSpecification : IRequestSpecification
    {
        public bool IsSatisfiedBy(object request)
        {
            var requestType = request as Type;
            if (requestType == null)
                return false;
            return typeof(ApiController).IsAssignableFrom(requestType);
        }
    }
}

The value of type HttpRequestMessage, for the Request property, is built using the following customization:

internal 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()));
    }
}

Packing everything into a composite Customization

Create a Customization composite as below - note that the order of AutoFixture Customizations matter:

internal class ApiControllerConventions : CompositeCustomization
{
    internal ApiControllerConventions()
        : base(
            new HttpRequestMessageCustomization(),
            new ApiControllerCustomization(),
            new AutoMoqCustomization())
    {
    }
}

Hope that helps.

这篇关于Automocking网页API 2控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆