我正在尝试在我的测试用例中自动模拟 ApiController 类。当我使用 WebApi1 时它工作得很好。我开始在新项目上使用 WebApi2,但在我尝试运行新测试后抛出了这个异常:
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)
我的测试代码:
[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);
}
如果我手动创建 sut,测试用例确实有效:
[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);
}
似乎在尝试模拟 ControllerContext.RequestContext.ClientCertificate 时出了点问题我已经尝试创建一个没有它的夹具(使用 AutoFixture .Without() 方法)但后来即使是旧测试也开始失败。
我的 AutoMoqDataAttribute:
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(new Fixture()
.Customize(new WebApiCustomization()))
{
}
}
WebApi 定制:
public class WebApiCustomization : CompositeCustomization
{
public WebApiCustomization()
: base(
new HttpRequestMessageCustomization(),
new AutoMoqCustomization())
{
}
}
HttpRequestMessage 自定义:
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();
})
);
}
}
用户 Controller :
/// <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);
}
}
最佳答案
注意: 原文answer需要为每个新的 ApiController 复制相同的定制。
通用方法
另一种方法是自动填充所有 ApiController 上的 Request
属性(从而避免剪切、复制和粘贴):
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);
}
}
}
HttpRequestMessage
类型的值,对于 Request
属性,是使用以下定制构建的:
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()));
}
}
将所有内容打包到复合定制中
如下所示创建自定义组合 - 注意 the order of AutoFixture Customizations matter :
internal class ApiControllerConventions : CompositeCustomization
{
internal ApiControllerConventions()
: base(
new HttpRequestMessageCustomization(),
new ApiControllerCustomization(),
new AutoMoqCustomization())
{
}
}
希望对您有所帮助。
关于c# - 自动模拟 Web Api 2 Controller ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19908385/