2009-06-04 9 views
12

私はこのように使用されているUrlHelperのextensionmethodのためのテストを書くことをしようとしている:単体テストUrl.Action

Url.Action<TestController>(x => x.TestAction()); 

しかし、私は正しくそれを設定することができないよう私は新しいUrlHelperを作成して、返されたURLが期待されたものであると主張することができます。これは私が持っているものですが、私は嘲笑を伴わないものにも開放されています。 ; O)

 [Test] 
    public void Should_return_Test_slash_TestAction() 
    { 
     // Arrange 
     RouteTable.Routes.Add("TestRoute", new Route("{controller}/{action}", new MvcRouteHandler())); 
     var mocks = new MockRepository(); 
     var context = mocks.FakeHttpContext(); // the extension from hanselman 
     var helper = new UrlHelper(new RequestContext(context, new RouteData()), RouteTable.Routes); 

     // Act 
     var result = helper.Action<TestController>(x => x.TestAction()); 

     // Assert 
     Assert.That(result, Is.EqualTo("Test/TestAction")); 
    } 

私はurlHelper.Actionにそれを変更しようとした(「テスト」、「TestAction」)が、私はそれが動作していない私のextensionmethodではありません知っているので、それはとにかく失敗します。 NUnitのは返します

NUnit.Framework.AssertionException: Expected string length 15 but was 0. Strings differ at index 0. 
Expected: "Test/TestAction" 
But was: <string.Empty> 

私はルートが登録されていることを確認し、作業と私は偽のHttpContextを作成するためのHanselmans拡張子を使用していています。私のUrlHelper拡張メソッドの外観は次のとおりです。

 public static string Action<TController>(this UrlHelper urlHelper, Expression<Func<TController, object>> actionExpression) where TController : Controller 
    { 
     var controllerName = typeof(TController).GetControllerName(); 
     var actionName = actionExpression.GetActionName(); 

     return urlHelper.Action(actionName, controllerName); 
    } 

    public static string GetControllerName(this Type controllerType) 
    { 
     return controllerType.Name.Replace("Controller", string.Empty); 
    } 

    public static string GetActionName(this LambdaExpression actionExpression) 
    { 
     return ((MethodCallExpression)actionExpression.Body).Method.Name; 
    } 

私はそれが動作するために紛失しているものについてのアイデア??? /Kristoffer

+0

Factory.CreateUrlHelperメソッドコードを投稿できますか? – nkirkes

答えて

11

内部的には、RouteCollectionオブジェクトがHttpResponseBaseのApplyAppPathModifierメソッドを呼び出しているため動作しません。Hanselmanの模擬コードではそのメソッドの期待値が設定されていないので、nullを返します。そのため、UrlHelperのActionメソッドへの呼び出しはすべて空の文字列を返します。修正点は、HttpResponseBaseモックのApplyAppPathModifierメソッドに期待値を設定して、渡された値だけを返すようにすることです。私はRhino Mocksのエキスパートではないので、構文については完全にはわかりません。上記のコードがあるべき

internal class FakeHttpContext : HttpContextBase 
{ 
    private HttpRequestBase _request; 
    private HttpResponseBase _response; 

    public FakeHttpContext() 
    { 
     _request = new FakeHttpRequest(); 
     _response = new FakeHttpResponse(); 
    } 

    public override HttpRequestBase Request 
    { 
     get { return _request; } 
    } 

    public override HttpResponseBase Response 
    { 
     get { return _response; } 
    } 
} 

internal class FakeHttpResponse : HttpResponseBase 
{ 
    public override string ApplyAppPathModifier(string virtualPath) 
    { 
     return virtualPath; 
    } 
} 

internal class FakeHttpRequest : HttpRequestBase 
{ 
    private NameValueCollection _serverVariables = new NameValueCollection(); 

    public override string ApplicationPath 
    { 
     get { return "/"; } 
    } 

    public override NameValueCollection ServerVariables 
    { 
     get { return _serverVariables; } 
    } 
} 

httpResponse.Setup(r => r.ApplyAppPathModifier(It.IsAny<string>())) 
    .Returns((string s) => s); 

それとも、あなただけの手巻きのモックを使用している場合、このようなものは動作します:あなたが部品番号を使用している場合、それはこのようになります。 UrlHelperの単体テストを行うためにHttpContextBaseを最小限に実装する必要があります。私はそれを試して、それは働いた。お役に立てれば。

1

これはあなたの質問に直接答えるものではありませんが、MVC Futuresアセンブリで使用できる汎用拡張メソッドを使用するのではなく、独自の汎用拡張メソッドを作成しようとしている理由はありますか? (Microsoft.Web.Mvc.dll)または実際には、ユニットテストのmsftの拡張メソッドを試していますか?

[編集1] 申し訳ありませんが、私はFuturesのHtmlヘルパー拡張について考えていました。

一方、同じ結果が得られるかどうかを調べるために、単体テストで手を試してみます。

[編集2] これはまだ完全には機能していませんが、爆発することはありません。結果は単に空の文字列を返すだけです。

public static string Action<TController>(this UrlHelper helper, Expression<Action<TController>> action) where TController : Controller 
{ 
    string result = BuildUrlFromExpression<TController>(helper.RequestContext, helper.RouteCollection, action); 
    return result; 
} 

public static string BuildUrlFromExpression<TController>(RequestContext context, RouteCollection routeCollection, Expression<Action<TController>> action) where TController : Controller 
{ 
    RouteValueDictionary routeValuesFromExpression = GetRouteValuesFromExpression<TController>(action); 
    VirtualPathData virtualPath = routeCollection.GetVirtualPath(context, routeValuesFromExpression); 
    if (virtualPath != null) 
    { 
     return virtualPath.VirtualPath; 
    } 
    return null; 
} 

public static RouteValueDictionary GetRouteValuesFromExpression<TController>(Expression<Action<TController>> action) where TController : Controller 
{ 
    if (action == null) 
    { 
     throw new ArgumentNullException("action"); 
    } 
    MethodCallExpression body = action.Body as MethodCallExpression; 
    if (body == null) 
    { 
     throw new ArgumentException("MvcResources.ExpressionHelper_MustBeMethodCall", "action"); 
    } 
    string name = typeof(TController).Name; 
    if (!name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)) 
    { 
     throw new ArgumentException("MvcResources.ExpressionHelper_TargetMustEndInController", "action"); 
    } 
    name = name.Substring(0, name.Length - "Controller".Length); 
    if (name.Length == 0) 
    { 
     throw new ArgumentException("MvcResources.ExpressionHelper_CannotRouteToController", "action"); 
    } 
    RouteValueDictionary rvd = new RouteValueDictionary(); 
    rvd.Add("Controller", name); 
    rvd.Add("Action", body.Method.Name); 
    AddParameterValuesFromExpressionToDictionary(rvd, body); 
    return rvd; 
} 

private static void AddParameterValuesFromExpressionToDictionary(RouteValueDictionary rvd, MethodCallExpression call) 
{ 
    ParameterInfo[] parameters = call.Method.GetParameters(); 
    if (parameters.Length > 0) 
    { 
     for (int i = 0; i < parameters.Length; i++) 
     { 
      Expression expression = call.Arguments[i]; 
      object obj2 = null; 
      ConstantExpression expression2 = expression as ConstantExpression; 
      if (expression2 != null) 
      { 
       obj2 = expression2.Value; 
      } 
      else 
      { 
       Expression<Func<object>> expression3 = Expression.Lambda<Func<object>>(Expression.Convert(expression, typeof(object)), new ParameterExpression[0]); 
       obj2 = expression3.Compile()(); 
      } 
      rvd.Add(parameters[i].Name, obj2); 
     } 
    } 
} 

そして最後に、ここで私が実行しているテストがあります:私は、私はまた、私は、MVCのソースからリッピングヘルパーメソッドと一緒にUrl.Action<TController>方法を、作成したthis link.

でスコットHanselman氏からいくつかのMVCのモックヘルパーを取りました:

[Test] 
    public void GenericActionLinkHelperTest() 
    { 
     RouteRegistrar.RegisterRoutesTo(RouteTable.Routes); 

     var mocks = new MockRepository(); 
     var context = mocks.FakeHttpContext(); // the extension from hanselman 

     var helper = new UrlHelper(new RequestContext(context, new RouteData()), RouteTable.Routes); 
     string result = helper.Action<ProjectsController>(x => x.Index()); 

     // currently outputs an empty string, so something is fudded up. 
     Console.WriteLine(result); 
    } 

出力が空の文字列である理由はまだわかりませんが、私は時間があるようにこれを乱し続けます。その間に解決策を見つけたら、私は知りたいと思うだろう。

+0

私の例を更新しましたが、私はあなたと同じ結果を得ました。あなたはその進歩と呼ぶことができると思います。私のルートが動作していることを確認して "〜/ Test/TestAction"と一致するので、なぜ空の文字列を返すのかまだ分かりません。 –

+0

ええ、なぜそれが空に戻ってくるのかわかりません。最初は私がこのテストを実行したプロジェクトでは、私はいくつかの奇妙なルートを持っていて、おそらくマッチを見つけることができなかったからだと思っていました。あなたは同じ結果を得ているので、ルーティングの問題であるかどうかはわかりません。私はもう少し周りに遊ぶよ。 – nkirkes

2

私はBuildUrlFromExpressionメソッドをテストすることができましたが、私はテストを実行する前に、私のRouteTable.Routesを登録するために必要な:

[ClassInitialize] 
public static void FixtureSetUp(TestContext @__testContext) 
{ 
    MvcApplication.RegisterRoutes(RouteTable.Routes); 
} 

次に/セットアップこれらのプロパティをスタブアウト:

HttpRequestBase request = mocks.PartialMock<HttpRequestBase>(); 
request.Stub(r => r.ApplicationPath).Return(string.Empty); 

HttpResponseBase response = mocks.PartialMock<HttpResponseBase>(); 
SetupResult.For(response.ApplyAppPathModifier(Arg<String>.Is.Anything)).IgnoreArguments().Do((Func<string, string>)((arg) => { return arg; })); 

後BuildUrlFromExpressionメソッドが期待どおりにulを返すことを確認します。