2009-06-04 17 views
12

मैं एक UrlHelper extensionmethod है कि इस तरह प्रयोग किया जाता है के लिए एक परीक्षण लिखने के लिए कोशिश कर रहा हूँ:Unittesting Url.Action (राइनो Mocks का उपयोग कर?)

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

हालांकि, मैं इसे सही ढंग से तो सेट नहीं लग सकता है कि मैं एक नया UrlHelper बना सकता हूं और फिर जोर दे सकता हूं कि लौटा हुआ यूआरएल अपेक्षित था। यही वह है जो मुझे मिला है लेकिन मैं किसी भी चीज़ के लिए खुला हूं जिसमें मॉकिंग भी शामिल नहीं है। , हे)

 [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> 

मैं सत्यापित किया है कि मार्ग पंजीकृत है और काम कर रहा है और मैं Hanselmans एक्सटेंशन का उपयोग कर रहा हूँ एक नकली HttpContext बनाने के लिए किया जाता है। यहाँ क्या मेरी UrlHelper की तरह लग रहे extentionmethod है: क्या मैं यह काम कर रहा करने के लिए याद आ रही है पर

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

कोई भी विचार ??? /क्रिस्टोफर

+0

क्या आप अपनी फैक्टरी पोस्ट कर सकते हैं। क्रेतेउरल हेल्पर विधि कोड? – nkirkes

उत्तर

11

कारण यह काम नहीं कर रहा है यह है कि आंतरिक रूप से रूटकोलेक्शन ऑब्जेक्ट HttpResponseBase पर ApplyAppPathModifier विधि को कॉल करता है।ऐसा लगता है कि हंसेलमैन का नकली कोड उस विधि पर कोई उम्मीद नहीं लगाता है, इसलिए यह शून्य हो जाता है, यही कारण है कि UrlHelper पर एक्शन विधि में आपकी सभी कॉल एक खाली स्ट्रिंग लौट रही हैं। यह तय करने के लिए कि HttpResponseBase mock की ApplyAppPathModifier विधि पर केवल उस मान को वापस करने के लिए यह तय करना होगा। मैं राइनो मोक्स विशेषज्ञ नहीं हूं इसलिए मैं वाक्यविन्यास पर पूरी तरह से यकीन नहीं कर रहा हूं। आप Moq का उपयोग कर रहे हैं, तो यह इस प्रकार दिखाई देगा:

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

या, यदि आप सिर्फ एक हाथ से लुढ़का नकली उपयोग करते हैं, कुछ इस तरह काम करेगा:

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

ऊपर कोड होना चाहिए UrlHelper के लिए यूनिट परीक्षण पास करने के लिए HttpContextBase का न्यूनतम आवश्यक कार्यान्वयन। मैंने कोशिश की और यह काम किया। उम्मीद है की यह मदद करेगा।

1

मुझे पता है कि यह सीधे आपके प्रश्न का उत्तर नहीं देता है, लेकिन क्या कोई कारण है कि आप एमवीसी फ्यूचर्स असेंबली में उपलब्ध एक का उपयोग करने के विरोध में अपनी सामान्य विस्तार विधि लिखने की कोशिश कर रहे हैं? (माइक्रोसॉफ्ट.Web.Mvc.dll) या आप वास्तव में यूनिट परीक्षण एमएसएफटी की विस्तार विधि की कोशिश कर रहे हैं?

[संपादित करें 1] क्षमा करें, मैं फ्यूचर्स में एचटीएमएल सहायक विस्तार के बारे में सोच रहा था।

इस बीच, मैं एक यूनिट परीक्षण में अपना हाथ आजमाऊंगा ताकि यह देखने के लिए कि मुझे एक ही परिणाम मिल रहा है या नहीं।

[संपादित करें 2] ठीक है, तो यह अभी तक पूरी तरह से काम नहीं कर रहा है, लेकिन यह उड़ नहीं रहा है। परिणाम बस एक खाली स्ट्रिंग लौट रहा है। मैं this link.

पर कुछ Mvc स्कॉट Hanselman से सहायकों मजाक ले लिया मैं भी बनाई गई एक Url.Action<TController> विधि, साथ सहायक के तरीकों के साथ मैं MVC स्रोत से फट:

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

और अंत में, यहाँ परीक्षण मैं चल रहा हूँ है :

[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 रजिस्टर करने के लिए की जरूरत:

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

के बाद: फिर इन गुणों/सेटअप बाहर ठूंठ

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

कि BuildUrlFromExpression विधि अपेक्षित के रूप में uls वापस आ गया।

संबंधित मुद्दे