gpt4 book ai didi

c# - 如何使用自定义模型 Binder 对路由进行单元测试

转载 作者:太空狗 更新时间:2023-10-30 01:10:00 26 4
gpt4 key购买 nike

我有一个自定义模型 Binder ,用于检查用户是否有权访问他要求的文档;我想知道如何测试使用此自定义 Binder 的路由?

我尝试进行此测试,但出现此错误:

MvcContrib.TestHelper.AssertionException : Value for parameter 'contract' did not match: expected 'Domain.Models.Contract' but was ''; no value found in the route context action parameter named 'contract' - does your matching route contain a token called 'contract'?

[SetUp]
public void Setup()
{
MvcApplication.RegisterModelBinders();
MvcApplication.RegisterRoutes(RouteTable.Routes);
}

[Test]
public void VersionEdit()
{
var contract = TestHelper.CreateContract();
var route = "~/Contract/" + contract.Id.ToString() + "/Version/Edit/" +
contract.Versions.Count;
route.ShouldMapTo<VersionController>(c => c.Edit(contract));
}

如果我尝试调试自定义 Binder ,则永远不会被调用。

我的路线定义:

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"VersionToken", // Route name
"Contract/{contractId}/Version/{version}/{action}/{token}", // URL with parameters
new { controller = "Version", action = "ViewContract", version = 1, token = UrlParameter.Optional } // Parameter defaults
);

routes.MapRoute(
"Version", // Route name
"Contract/{contractId}/Version/{version}/{action}", // URL with parameters
new { controller = "Version", action = "Create", version = UrlParameter.Optional } // Parameter defaults
);

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

if (HttpContext.Current != null && !HttpContext.Current.IsDebuggingEnabled) routes.IgnoreRoute("CI");
}

我的模型 Binder :

public static void RegisterModelBinders()
{
var session = (ISession)DependencyResolver.Current.GetService(typeof(ISession));
var authService = (IAuthenticationService)DependencyResolver.Current.GetService(typeof(IAuthenticationService));
System.Web.Mvc.ModelBinders.Binders[typeof (Contract)] = new ContractModelBinder(session, authService);
}

public class ContractModelBinder : DefaultModelBinder
{
private readonly ISession _session;
private readonly IAuthenticationService _authService;
public ContractModelBinder(ISession session, IAuthenticationService authService)
{
_session = session;
_authService = authService;
}

public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var contractId = GetValue(bindingContext, "contractId");
var version = GetA<int>(bindingContext,"version");
var token = GetValue(bindingContext, "token");

var contract = _session.Single<Contract>(contractId);
if (contract == null)
{
throw new HttpException(404, "Not found");
}
if (contract.Versions.Count < version.Value)
{
throw new HttpException(404, "Not found");
}
contract.RequestedVersionNumber = version.Value;
if(token == null)
{
var user = _authService.LoggedUser();
if (user == null) throw new HttpException(401, "Unauthorized");
if (contract.CreatedBy == null || !contract.CreatedBy.Id.HasValue || contract.CreatedBy.Id.Value != user.Id)
{
throw new HttpException(403, "Forbidden");
}
}
else
{
contract.RequestedToken = token;
var userToken = contract.RequestedVersion.Tokens.SingleOrDefault(x => x.Token == token);
if (userToken == null)
{
throw new HttpException(401, "Unauthorized");
}
}

return contract;
}

private static T? GetA<T>(ModelBindingContext bindingContext, string key) where T : struct, IComparable
{
if (String.IsNullOrEmpty(key)) return null;
//Try it with the prefix...
var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + "." + key);
//Didn't work? Try without the prefix if needed...
if (valueResult == null && bindingContext.FallbackToEmptyPrefix)
{
valueResult = bindingContext.ValueProvider.GetValue(key);
}
if (valueResult == null)
{
return null;
}
return (T)valueResult.ConvertTo(typeof(T));
}

private static string GetValue(ModelBindingContext bindingContext, string key)
{
if (String.IsNullOrEmpty(key)) return null;
//Try it with the prefix...
var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + "." + key);
//Didn't work? Try without the prefix if needed...
if (valueResult == null && bindingContext.FallbackToEmptyPrefix)
{
valueResult = bindingContext.ValueProvider.GetValue(key);
}
if (valueResult == null)
{
return null;
}
return valueResult.AttemptedValue;
}
}

最佳答案

当测试路由时,MvcContrib TestHelper 不会调用 MVC 管道和模型绑定(bind)器。模型绑定(bind)器应该单独进行单元测试。绑定(bind)独立于路由,一旦实例化 Controller 并调用操作就会发生。

在这个例子中,你是单元测试路线。因此,您需要确保 ~/Contract/5/Version/Edit/3 正确映射到 VersionController 上的 Edit 操作是这样完成的:

"~/Contract/5/Version/Edit/3".ShouldMapTo<VersionController>(c => c.Edit(null));

关于c# - 如何使用自定义模型 Binder 对路由进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5616288/

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