2011-04-11 22 views
4

我有一個自定義模型聯編程序,用於檢查用戶是否有權訪問他要求的文檔;我想知道如何測試使用此自定義聯編程序的路線?如何使用自定義模型聯編程序對路線進行單元測試

我嘗試用這個測試,但我得到這個錯誤:

MvcContrib.TestHelper.AssertionException :價值參數「契約」沒有 不匹配:預計 「Domain.Models.Contract」但''; 在路由上下文中找不到值 名爲'contract'的操作參數 - 您的匹配路由中是否包含 令牌稱爲'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)); 
} 

如果我嘗試調試定製綁定不會被調用。

我的路由定義:

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

我的模型綁定:

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; 
     } 
    } 
+1

你能告訴我們你的路由定義以及如何註冊模型綁定? – 2011-04-20 06:28:30

+0

@Sergi我添加了路徑定義和模型聯編程序 – VinnyG 2011-04-20 13:32:22

回答

5

在測試路線MvcContrib TestHelper不會調用MVC管道和模型綁定。模型活頁夾應單獨進行單元測試。綁定與路由分離並且一旦控制器被實例化並且被調用,就發生綁定。

在這個例子中你是單元測試路線。因此,所有你需要確保的是,~/Contract/5/Version/Edit/3正確映射到您VersionControllerEdit作用,這就像下面這樣:

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

,因此我不必測試它是否映射到我的操作的正確參數? – VinnyG 2011-04-20 13:28:39

+0

@VinnyG,這是模型活頁夾的工作。你應該測試一下,但是要用一個單獨的單元測試來測試你的路線。 – 2011-04-20 13:32:29

+0

我明白你的意思,我已經對自定義聯編程序進行了測試,但我不確定這是否是一個好的答案。是的,我的測試通過,但爲什麼它應該指向一個空參數? – VinnyG 2011-04-20 14:34:31

相關問題