gpt4 book ai didi

unit-testing - 使用服务定位器时如何为 ActionFilter 编写单元测试

转载 作者:行者123 更新时间:2023-12-01 07:17:58 26 4
gpt4 key购买 nike

我打算写一个 ActionFilter用于业务验证,其中一些服务将通过服务定位器解决(我知道这不是一个好的做法,我尽可能避免使用服务定位器模式,但在这种情况下我想使用它)。
OnActionExecuting过滤器的方法是这样的:

    public override void OnActionExecuting(ActionExecutingContext actionContext)
{
// get validator for input;
var validator = actionContext.HttpContext.RequestServices.GetService<IValidator<TypeOfInput>>();// i will ask another question for this line
if(!validator.IsValid(input))
{
//send errors
}
}

是否可以为上述 ActionFilter 编写单元测试如何?

最佳答案

这是一个关于如何创建模拟(使用 XUnit 和 Moq 框架)来验证 IsValid 的示例。方法被调用并且模拟返回 false .

using Dealz.Common.Web.Tests.Utils;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using System;
using Xunit;

namespace Dealz.Common.Web.Tests.ActionFilters
{
public class TestActionFilter
{
[Fact]
public void ActionFilterTest()
{
/****************
* Setup
****************/

// Create the userValidatorMock
var userValidatorMock = new Mock<IValidator<User>>();
userValidatorMock.Setup(validator => validator
// For any parameter passed to IsValid
.IsValid(It.IsAny<User>())
)
// return false when IsValid is called
.Returns(false)
// Make sure that `IsValid` is being called at least once or throw error
.Verifiable();

// If provider.GetService(typeof(IValidator<User>)) gets called,
// IValidator<User> mock will be returned
var serviceProviderMock = new Mock<IServiceProvider>();
serviceProviderMock.Setup(provider => provider.GetService(typeof(IValidator<User>)))
.Returns(userValidatorMock.Object);

// Mock the HttpContext to return a mockable
var httpContextMock = new Mock<HttpContext>();
httpContextMock.SetupGet(context => context.RequestServices)
.Returns(serviceProviderMock.Object);


var actionExecutingContext = HttpContextUtils.MockedActionExecutingContext(httpContextMock.Object, null);

/****************
* Act
****************/
var userValidator = new ValidationActionFilter<User>();
userValidator.OnActionExecuting(actionExecutingContext);

/****************
* Verify
****************/

// Make sure that IsValid is being called at least once, otherwise this throws an exception. This is a behavior test
userValidatorMock.Verify();

// TODO: Also Mock HttpContext.Response and return in it's Body proeprty a memory stream where
// your ActionFilter writes to and validate the input is what you desire.
}
}

class User
{
public string Username { get; set; }
}

class ValidationActionFilter<T> : IActionFilter where T : class, new()
{
public void OnActionExecuted(ActionExecutedContext context)
{
throw new NotImplementedException();
}

public void OnActionExecuting(ActionExecutingContext actionContext)
{
var type = typeof(IValidator<>).MakeGenericType(typeof(T));

var validator = (IValidator<T>)actionContext.HttpContext
.RequestServices.GetService<IValidator<T>>();

// Get your input somehow
T input = new T();

if (!validator.IsValid(input))
{
//send errors
actionContext.HttpContext.Response.WriteAsync("Error");
}
}
}

internal interface IValidator<T>
{
bool IsValid(T input);
}
}

HttpContextUtils.cs

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Collections.Generic;

namespace Dealz.Common.Web.Tests.Utils
{
public class HttpContextUtils
{
public static ActionExecutingContext MockedActionExecutingContext(
HttpContext context,
IList<IFilterMetadata> filters,
IDictionary<string, object> actionArguments,
object controller
)
{
var actionContext = new ActionContext() { HttpContext = context };

return new ActionExecutingContext(actionContext, filters, actionArguments, controller);
}
public static ActionExecutingContext MockedActionExecutingContext(
HttpContext context,
object controller
)
{
return MockedActionExecutingContext(context, new List<IFilterMetadata>(), new Dictionary<string, object>(), controller);
}
}
}

如您所见,这相当困惑,您需要创建大量模拟来模拟实际类的不同响应,才能单独测试 ActionAttribute。

关于unit-testing - 使用服务定位器时如何为 ActionFilter 编写单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38285815/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com