2009-03-21 23 views
56

शायद यह आंखों की एक और जोड़ी की आवश्यकता होने का मामला बनने जा रहा है। मुझे कुछ याद आना चाहिए, लेकिन मुझे पता नहीं चल सकता कि इस तरह की चीज़ का परीक्षण क्यों नहीं किया जा सकता है। मैं मूल रूप से यह सुनिश्चित करें कि अप्रमाणित उपयोगकर्ताओं [अधिकृत] विशेषता के साथ नियंत्रक चिह्नित करके देखने तक नहीं पहुँच सकता कोशिश कर रहा हूँ और मैं परीक्षण करने के लिए इस का उपयोग करते हुए निम्न कोड कोशिश कर रहा हूँ:यूनिट परीक्षण एएसपी.Net एमवीसी प्राधिकरण विशेषता लॉगिन पृष्ठ पर रीडायरेक्ट सत्यापित करने के लिए

[Fact] 
public void ShouldRedirectToLoginForUnauthenticatedUsers() 
{ 
    var mockControllerContext = new Mock<ControllerContext>() 
         { DefaultValue = DefaultValue.Mock }; 
    var controller = new MyAdminController() 
       {ControllerContext = mockControllerContext.Object}; 
    mockControllerContext.Setup(c => 
       c.HttpContext.Request.IsAuthenticated).Returns(false); 
    var result = controller.Index(); 
    Assert.IsAssignableFrom<RedirectResult>(result); 
} 

RedirectResult मैं देख रहा हूँ क्योंकि किसी प्रकार का संकेत है कि उपयोगकर्ता को लॉगिन फॉर्म पर रीडायरेक्ट किया जा रहा है, लेकिन इसके बजाय एक व्यूअरसल्ट हमेशा वापस आ जाता है और जब डिबगिंग मैं देख सकता हूं कि इंडेक्स() विधि सफलतापूर्वक हिट हो जाती है भले ही उपयोगकर्ता प्रमाणीकृत नहीं है।

क्या मैं कुछ गलत कर रहा हूं? गलत स्तर पर परीक्षण? क्या मुझे इस तरह की चीज़ के लिए मार्ग स्तर पर परीक्षण करना चाहिए?

मुझे पता है कि [अधिकृत] विशेषता काम कर रही है, क्योंकि जब मैं पृष्ठ को स्पिन करता हूं, तो लॉगिन स्क्रीन वास्तव में मुझ पर मजबूर होती है - लेकिन मैं इसे परीक्षण में कैसे सत्यापित करूं?

नियंत्रक और अनुक्रमणिका विधि बहुत सरल हैं ताकि मैं व्यवहार को सत्यापित कर सकूं। मैं उन्हें संपूर्णता के लिए शामिल किया है:

[Authorize] 
public class MyAdminController : Controller 
{ 
    public ActionResult Index() 
    { 
     return View(); 
    } 
} 

सराहना की कोई मदद ...

उत्तर

88

तुम गलत स्तर पर परीक्षण कर रहे हैं। [अधिकृत] विशेषता यह सुनिश्चित करती है कि रूटिंग इंजन कभी भी अनधिकृत उपयोगकर्ता के लिए उस विधि का आह्वान नहीं करेगा - रीडायरेक्ट रीसेट वास्तव में मार्ग से आ रहा है, न कि आपके नियंत्रक विधि से।

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

संपादित करें: यदि आप अपने यूनिट परीक्षणों में विशेषता की उपस्थिति को सत्यापित करना चाहते हैं, तो आपको निम्नानुसार अपने नियंत्रक विधियों का निरीक्षण करने के लिए प्रतिबिंब का उपयोग करना होगा। यह उदाहरण MVC2 के साथ स्थापित 'नया एएसपी.नेट एमवीसी 2 प्रोजेक्ट' डेमो में ChangePassword POST विधि पर प्राधिकृत विशेषता की उपस्थिति को सत्यापित करेगा।

[TestFixture] 
public class AccountControllerTests { 

    [Test] 
    public void Verify_ChangePassword_Method_Is_Decorated_With_Authorize_Attribute() { 
     var controller = new AccountController(); 
     var type = controller.GetType(); 
     var methodInfo = type.GetMethod("ChangePassword", new Type[] { typeof(ChangePasswordModel) }); 
     var attributes = methodInfo.GetCustomAttributes(typeof(AuthorizeAttribute), true); 
     Assert.IsTrue(attributes.Any(), "No AuthorizeAttribute found on ChangePassword(ChangePasswordModel model) method"); 
    } 
} 
+0

धन्यवाद डायलन - मैंने सोचा कि मैं गलत स्तर पर परीक्षण कर रहा हूं। मैं "मानते हुए" के विचार से खुश हूं कि अगर नियंत्रक हिट हो जाता है, तो उपयोगकर्ता प्रमाणित होता है। पीएस क्या आप वाकई ढांचे में परीक्षण कर रहे हैं? मैं वैध आईप्रिंसिपल की आपूर्ति करने वाले कुछ परीक्षण देख सकता हूं, लेकिन कोई भी जो अवैध मामले का परीक्षण नहीं करता ;-) – RobertTheGrey

+2

एर, नहीं ... वास्तव में परीक्षण केस को सत्यापित नहीं किया है; मैं एमवीसी गिरोह पर भरोसा कर रहा हूं कि यह सही हो गया है। मेरी गलती! –

+3

मुझे यह जवाब पसंद है कि यह सही दृष्टिकोण क्यों नहीं है, लेकिन मैं तर्क पर आश्वस्त नहीं हूं "सुविधा ढांचे और कार्यों में परीक्षण की जाती है"। मुझे भरोसा है कि विशेषता ठीक से काम कर रही है, यह ढांचा का काम है, लेकिन मैं अभी भी यह कहना चाहूंगा कि मेरे नियंत्रकों के कौन से तरीके विशेषता का उपयोग करते हैं। – Mathias

3

क्यों न सिर्फ प्रतिबिंब का उपयोग नियंत्रक वर्ग और/या कार्रवाई विधि परीक्षण किए जाने पर [Authorize] विशेषता के लिए देखने के लिए? ढांचे को मानते हुए यह सुनिश्चित करता है कि विशेषता सम्मानित है, यह करना सबसे आसान काम होगा।

+1

यहां दो अलग-अलग चीजों का परीक्षण किया जा रहा है। (1) परीक्षण करें कि एक कस्टम विशेषता जो करता है वह करता है; और (2) यह एक नियंत्रक/कार्रवाई विशेषता के साथ सजाया रहता है। आप (2) का जवाब दे रहे हैं, लेकिन मुझे लगता है कि डारियो क्विंटाना द्वारा पोस्ट किया गया लिंक (1) का सबसे अच्छा जवाब है। –

+0

असली दुनिया में, प्राधिकरण विशेषता के साथ एनोटेशन अनुरोध/नियंत्रक क्रियाओं को अधिकृत करने के लिए उपयोग किया जाने वाला एकमात्र तरीका नहीं है। –

22

ठीक है आप गलत स्तर पर परीक्षण कर रहे हैं लेकिन इसका परीक्षण जो समझ में आता है। मेरा मतलब है, अगर मैं प्राधिकरण (भूमिकाएं = "सुपरहीरो") विशेषता के साथ एक विधि को ध्वजांकित करता हूं, तो मुझे इसे फ़्लैग करने पर वास्तव में परीक्षण की आवश्यकता नहीं होती है। मैं क्या सोचता हूं (मुझे लगता है) यह जांचना है कि एक अनधिकृत उपयोगकर्ता के पास पहुंच नहीं है और वह अधिकृत उपयोगकर्ता करता है।

इस तरह एक परीक्षण एक अनधिकृत उपयोगकर्ता के लिए:

// Arrange 
var user = SetupUser(isAuthenticated, roles); 
var controller = SetupController(user); 

// Act 
SomeHelper.Invoke(controller => controller.MyAction()); 

// Assert 
Assert.AreEqual(401, 
    controller.ControllerContext.HttpContext.Response.StatusCode, "Status Code"); 

खैर, यह आसान नहीं है और यह मुझे 10 घंटे लगे, लेकिन यहाँ यह है। मुझे उम्मीद है कि कोई इससे लाभ उठा सकता है या मुझे किसी अन्य पेशे में जाने के लिए मना सकता है।- :) Btw (राइनो नकली मैं उपयोग कर रहा हूँ)

[Test] 
public void AuthenticatedNotIsUserRole_Should_RedirectToLogin() 
{ 
    // Arrange 
    var mocks = new MockRepository(); 
    var controller = new FriendsController(); 
    var httpContext = FakeHttpContext(mocks, true); 
    controller.ControllerContext = new ControllerContext 
    { 
     Controller = controller, 
     RequestContext = new RequestContext(httpContext, new RouteData()) 
    }; 

    httpContext.User.Expect(u => u.IsInRole("User")).Return(false); 
    mocks.ReplayAll(); 

    // Act 
    var result = 
     controller.ActionInvoker.InvokeAction(controller.ControllerContext, "Index"); 
    var statusCode = httpContext.Response.StatusCode; 

    // Assert 
    Assert.IsTrue(result, "Invoker Result"); 
    Assert.AreEqual(401, statusCode, "Status Code"); 
    mocks.VerifyAll(); 
} 

हालांकि, इस सहायक समारोह के बिना बहुत उपयोगी नहीं thats:

public static HttpContextBase FakeHttpContext(MockRepository mocks, bool isAuthenticated) 
{ 
    var context = mocks.StrictMock<HttpContextBase>(); 
    var request = mocks.StrictMock<HttpRequestBase>(); 
    var response = mocks.StrictMock<HttpResponseBase>(); 
    var session = mocks.StrictMock<HttpSessionStateBase>(); 
    var server = mocks.StrictMock<HttpServerUtilityBase>(); 
    var cachePolicy = mocks.Stub<HttpCachePolicyBase>(); 
    var user = mocks.StrictMock<IPrincipal>(); 
    var identity = mocks.StrictMock<IIdentity>(); 
    var itemDictionary = new Dictionary<object, object>(); 

    identity.Expect(id => id.IsAuthenticated).Return(isAuthenticated); 
    user.Expect(u => u.Identity).Return(identity).Repeat.Any(); 

    context.Expect(c => c.User).PropertyBehavior(); 
    context.User = user; 
    context.Expect(ctx => ctx.Items).Return(itemDictionary).Repeat.Any(); 
    context.Expect(ctx => ctx.Request).Return(request).Repeat.Any(); 
    context.Expect(ctx => ctx.Response).Return(response).Repeat.Any(); 
    context.Expect(ctx => ctx.Session).Return(session).Repeat.Any(); 
    context.Expect(ctx => ctx.Server).Return(server).Repeat.Any(); 

    response.Expect(r => r.Cache).Return(cachePolicy).Repeat.Any(); 
    response.Expect(r => r.StatusCode).PropertyBehavior(); 

    return context; 
} 

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

मुझे उत्सुकता है कि यह इतना कठिन क्यों है एक कथित तौर पर "टेस्टेबल" ढांचे में।

+0

डब्ल्यूटीएफ वास्तव में, सौभाग्य से अगर आप इसके साथ चिपके रहते हैं तो आप इसके चारों ओर और उसके बाद के सभी मुद्दों के आसपास एक रास्ता खोज सकते हैं, जैसा मैंने किया था। मेरे जीथब प्रोजेक्ट पर एक लुक लें: https://github.com/ibrahimbensalah/Xania.AspNet.Simulator/blob/master/Xania.AspNet.Simulator.Tests/ –

+0

यह पोस्ट लगभग पूरी तरह से [लिंक जैसा ही है ] (https://web.archive.org/web/20130213143434/http://darioquintana.com.ar/blogging/2009/05/23/aspnet-mvc-testing-a- कस्टम- प्राधिकरण- फ़िल्टर) में प्रस्तुत किया गया @Dario द्वारा पोस्ट। क्या आपने इसे स्वयं विकसित किया? –

+0

हां, यह सब मेरे द्वारा विकसित किया गया है, और अभी भी सक्रिय रूप से विकास में है। वर्तमान में प्रमाणीकरण, मॉडल बाइंडर्स, अनुरोध सत्यापन, रेज़र प्रतिपादन से एमवीसी 4 और एमवीसी 5 का समर्थन .... –

1

मैं, डिलन के जवाब से सहमत नहीं है क्योंकि 'उपयोगकर्ता में लॉग इन होना चाहिए' मतलब यह नहीं है कि

सुनिश्चित करने के लिए 'नियंत्रक विधि AuthorizeAttribute साथ टिप्पणी की जाती है' जब आप कॉल 'उपयोगकर्ता में लॉग इन होना चाहिए' कार्रवाई विधि, ASP.NET MVC ढांचे कुछ इस तरह करता है (बस पर पकड़, यह सरल अंत में मिल जाएगा)

let $filters = All associated filter attributes which implement 
       IAuthorizationFilter 

let $invoker = instance of type ControllerActionInvoker 
let $ctrlCtx = instance or mock of type ControllerContext 
let $actionDesc = instance or mock of type ActionDescriptor 
let $authzCtx = $invoker.InvokeAuthorizationFilters($ctrlCtx, $filters, $actionDesc); 

then controller action is authorized when $authzCtx.Result is not null 

यह एक काम कर ग # कोड में इस छद्म स्क्रिप्ट को लागू करना मुश्किल है। शायद, Xania.AspNet.Simulator इस तरह एक परीक्षण स्थापित करने के लिए वास्तव में आसान बनाता है और कवर के तहत वास्तव में इन चरणों को निष्पादित करता है। यहाँ एक उदाहरण है।

पहले nuget से पैकेज (संस्करण लेखन के समय 1.4.0-beta4)

PM> स्थापित पैकेज Xania.AspNet.Simulator -पूर्व

फिर अपने परीक्षण स्थापित विधि इस तरह दिख सकती है (मान लें कि एनयूनीट और फ्लुएंटएस्सेरशन स्थापित हैं):

[Test] 
public void AnonymousUserIsNotAuthorized() 
{ 
    // arrange 
    var action = new ProfileController().Action(c => c.Index()); 
    // act 
    var result = action.GetAuthorizationResult(); 
    // assert 
    result.Should().NotBeNull(); 
} 

[Test] 
public void LoggedInUserIsAuthorized() 
{ 
    // arrange 
    var action = new ProfileController().Action(c => c.Index()) 
    // simulate authenticated user 
    .Authenticate("user1", new []{"role1"}); 
    // act 
    var result = action.GetAuthorizationResult(); 
    // assert 
    result.Should().BeNull(); 
} 
संबंधित मुद्दे

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