2012-08-02 14 views
10

Url.Link मैं नियंत्रक गई कार्रवाई के बाद की हैपरीक्षण WebAPI नियंत्रक

public void Post(Dto model) 
{ 
    using (var message = new MailMessage()) 
    { 
     var link = Url.Link("ConfirmAccount", new { model.Id }); 

     message.To.Add(model.ToAddress); 
     message.IsBodyHtml = true; 
     message.Body = string.Format(@"<p>Click <a href=""{0}"">here</a> to complete your registration.<p><p>You may also copy and paste this link into your browser.</p><p>{0}</p>", link); 

     MailClient.Send(message); 
    } 
} 

यह परीक्षण करने के मैं सेटअप करने के लिए नियंत्रक संदर्भ

var httpConfiguration = new HttpConfiguration(new HttpRouteCollection { { "ConfirmAccount", new HttpRoute() } }); 
var httpRouteData = new HttpRouteData(httpConfiguration.Routes.First()); 
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "http://localhost"); 
sut = new TheController 
{ 
    ControllerContext = new HttpControllerContext(httpConfiguration, httpRouteData, httpRequestMessage), 
    MailClient = new SmtpClient { PickupDirectoryLocation = location } 
}; 

इस रचना का परीक्षण करने के लिए सेटअप का एक बहुत की तरह लगता है की जरूरत है एक लिंक का क्या ऐसा करने का कोई क्लीनर तरीका है? मैंने इन-मेमोरी सर्वरों के बारे में पढ़ा है लेकिन ऐसा लगता है कि यह सीधे नियंत्रक का परीक्षण करने से httpclient पर अधिक लागू होता है।

+0

+1 मैंने सोचा कि आरईएसटी सेवाओं का पूरा बिंदु लिंक करने योग्य संसाधनों की अनुमति देना था। मैं वेबएपीआई लिंक/यूआरएल यूटिलिटीज से वास्तव में नाखुश हूं। मार्ग के नाम का संदर्भ इतना नाजुक लगता है और परीक्षण की कहानी उतनी ही दर्दनाक है। उम्मीद है कि कुछ सुधार आ रहे हैं ... –

उत्तर

2

मैं एक ही मूर्खता में भाग रहा हूं। सभी संदर्भ मैं पा सकते हैं कि आप अनुरोध/नियंत्रक को मॉक करना चाहते हैं, जो कि (जैसा कि आपने बताया) बहुत सारे काम हैं।

विशिष्ट संदर्भ:

मुझे वास्तविक मॉकिंग फ्रेमवर्क का प्रयास करने के लिए चारों ओर नहीं मिला है, इसलिए मेरे पास मेरे नियंत्रक को "निर्माण" करने के लिए एक सहायक वर्ग है। तो

sut = new TheController { ... } 

के बजाय मैं की तरह कुछ का उपयोग करें:

// actually rolled together to `sut = MyTestSetup.GetController(method, url)` 
sut = new TheController()... 
MyTestSetup.FakeRequest(sut, HttpMethod.Whatever, "~/the/expected/url"); 

संदर्भ के लिए, विधि मूल रूप से है:

public void FakeRequest(ApiController controller, HttpMethod method = null, string requestUrl = null, string controllerName = null) { 
    HttpConfiguration config = new HttpConfiguration(); 
    // rebuild the expected request 
    var request = new HttpRequestMessage(null == method ? this.requestMethod : method, string.IsNullOrWhiteSpace(requestUrl) ? this.requestUrl : requestUrl); 
    //var route = System.Web.Routing.RouteTable.Routes["DefaultApi"]; 
    var route = config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}"); 

    // TODO: get from application? maybe like https://stackoverflow.com/a/5943810/1037948 
    var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", string.IsNullOrWhiteSpace(controllerName) ? this.requestController : controllerName } }); 

    controller.ControllerContext = new HttpControllerContext(config, routeData, request); 

    // attach fake request 
    controller.Request = request; 
    controller.Request.Properties[/* "MS_HttpConfiguration" */ HttpPropertyKeys.HttpConfigurationKey] = config; 
} 
+0

अब मैं नियंत्रक में लिंक बनाने के बजाय टेक्स्ट बनाने के लिए [RazorGenerator] (http://razorgenerator.codeplex.com/) का उपयोग कर रहा हूं। –

12

नीचे किसी भी प्रकार के बिना UrlHelper का परीक्षण करने के लिए आवश्यक निरपेक्ष न्यूनतम कोड है मॉकिंग लाइब्रेरी का। जिस चीज ने मुझे फेंक दिया (और मुझे ट्रैक करने में कुछ समय लगा) यह था कि आपको अनुरोध के IHttpRouteData को सेट करने की आवश्यकता है। यदि आप IHttpRoute उदाहरण नहीं हैं तो वर्चुअल पथ उत्पन्न करने में असफल रहेगा जिसके परिणामस्वरूप एक खाली यूआरएल होगा।

public class FooController : ApiController 
    { 
     public string Get() 
     { 
      return Url.Link(RouteNames.DefaultRoute, new { controller = "foo", id = "10" }); 
     } 
    } 

    [TestFixture] 
    public class FooControllerTests 
    { 
     FooController controller; 

     [SetUp] 
     public void SetUp() 
     { 
      var config = new HttpConfiguration(); 

      config.Routes.MapHttpRoute(
       name: "Default", 
       routeTemplate: "api/{controller}/{id}", 
       defaults: new { id = RouteParameter.Optional }); 

      var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost"); 
      request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config; 
      request.Properties[HttpPropertyKeys.HttpRouteDataKey] = new HttpRouteData(new HttpRoute()); 

      controller = new FooController 
      { 
       Request = request 
      }; 
     } 

     [Test] 
     public void Get_returns_link() 
     { 
      Assert.That(controller.Get(), Is.EqualTo("http://localhost/api/foo/10")); 
     } 
    } 
+6

वेब api2 के बाद से इस पर कोई अपडेट आया? – GetFuzzy

+0

मुझे अपने 'नियंत्रक डिस्क्रिप्टर' सहित 'FooController' की' नियंत्रक कॉन्टेक्स्ट 'संपत्ति भी बनाना था। मुझे इस कोड को विरासत में मिला है और मुझे यकीन नहीं है कि मैं कौन सी वेब एपीआई का उपयोग कर रहा हूं, लेकिन यह एमवीसी 4 है। –

+0

@ गेटफज़ी थोड़ी देर हो चुकी है, लेकिन मुझे अभी यह पता चला है और मैं जवाब जोड़ रहा हूं। – krillgar

11

मैं वेब एपीआई 2.0 के साथ इस दृष्टिकोण का उपयोग शुरू कर दिया।

यदि आप एक मॉकिंग लाइब्रेरी का उपयोग कर रहे हैं (और आपको वास्तव में किसी भी वास्तविक विश्व इकाई परीक्षण के लिए चाहिए), तो आप UrlHelper ऑब्जेक्ट को सीधे नकल करने में सक्षम हैं क्योंकि virtual पर सभी विधियां हैं।

var mock = new Mock<UrlHelper>(); 
mock.Setup(m => m.Link(It.IsAny<string>(), It.IsAny<object>())).Returns("test url"); 

var controller = new FooController { 
    Url = mock.Object 
}; 

यह है कि दृष्टिकोण के साथ के रूप में, आप हर नाम है कि आप उपयोग कर रहे config के लिए मार्गों को जोड़ने की आवश्यकता बेन फोस्टर के जवाब की तुलना में कहीं क्लीनर समाधान है,। यह आसानी से बदल सकता है या स्थापित करने के लिए हास्यास्पद रूप से बड़ी संख्या में मार्ग हो सकता है।

+0

स्वीकार्य उत्तर होना चाहिए। सरल और सुरुचिपूर्ण। मुझे यह कोड भी चाहिए। var संदर्भ = नया HttpRequestContext {url = mockUrlHelper.Object}; अनुरोध। प्रॉपर्टीज। जोड़ें (HttpPropertyKeys.RequestContextKey, संदर्भ); – CountZero

+0

@CountZero आपको इसकी आवश्यकता क्यों हुई? यदि आप इसे अपने उत्तर के रूप में जोड़ना चाहते हैं, और मेरा निर्माण करना चाहते हैं, तो यह अच्छा हो सकता है, या हम इसे यहां जोड़ सकते हैं। आप तक, लेकिन कुछ संदर्भ (कोई इरादा नहीं है) सहायक होगा। – krillgar

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