2016-03-22 21 views
5

मेरे पास वेबएपीआई एमवीसी प्रोजेक्ट में एक जटिल विधि है। यह उपयोगकर्ता प्रमाणीकरण के लिए दूरस्थ सर्वर को मारने सहित कई चीजें करता है। इसके परिणामों के आधार पर, यह या तो एक रीडायरेक्ट (एक पृष्ठ), एक स्ट्रिंग त्रुटि संदेश, या सभी प्रमाणीकरण बंदर-व्यवसाय का प्रतिनिधित्व करने वाली वस्तु देता है।[testMethod] से async को कैसे कॉल करें?

ब्राउज़र से कॉल होने पर यह बहुत अच्छा काम करता है। यह डीबग में भी ठीक काम करता है। मैं इसे एक रीडायरेक्ट भी लिख सकता हूं और उसे "मैन्युअल" कह सकता हूं, जो भी आवश्यक पैराम में गुजर रहा है।

जिस मुद्दे में मैं चल रहा हूं वह इसे एक परीक्षण प्रोजेक्ट वीएस से बुला रहा है जब मैंने वेबएपीआई प्रोजेक्ट बनाया था। मुझे संदेह है कि ऐसा इसलिए है क्योंकि सभी async और await की वजह से फेंक दिया गया है। जब यह इसमें जाता है, अंततः यह "वस्तु के उदाहरण के लिए सेट ऑब्जेक्ट" त्रुटि के साथ वापस आता है।

चूंकि यह किसी अन्य संदर्भ में काम करता है, मुझे लगता है कि ऐसा इसलिए है क्योंकि यह एक परीक्षण परियोजना के अंदर है और इसकी प्रतीक्षा की जानी चाहिए। क्या कोई मुझे इस पर कोई सलाह दे सकता है?

संपादित करें: बहुत विशिष्ट होना, इसे यहाँ कोड की दूसरी पंक्ति पर विफल रहने के है:

BoxConfig boxConfig = new BoxConfig(ClientID, ClientSecret, enterpriseID, prvt, JWTPublicKeyPass, JWTPublicKeyID); 
BoxJWTAuth boxJWT = new BoxJWTAuth(boxConfig); //This is a JSON web token and is needed to authorize the enterprise level app user. 

कोड संदर्भ:

यह Box.com एपीआई का लाभ है। BoxJWT कॉल एक JSON वेब टोकन बनाता है। मुझे नहीं पता कि प्रक्रिया में यह कहां विफल रहा है क्योंकि जब मैं इसके माध्यम से पता लगाता हूं, तो यह मुझे PEMReader.cs, आदि जैसी चीजों के लिए कोड नहीं दिखा सकता है (जिसे क्रिप्टो, उछाल वाले महल के साथ करना है)। लेकिन बहुत विशेष रूप से, त्रुटि संदेश विवरण का कहना है कि स्रोत Box.V2.JWTAuth.PEMPasswordFinder.GetPassword()

+2

अभी तक आपका प्रश्न बहुत सार है। कृपया अपने कोड के एक [न्यूनतम, पूर्ण, और सत्यापन योग्य उदाहरण] (http://stackoverflow.com/help/mcve) शामिल करें। – Igor

+1

डुप्लिकेट? http://stackoverflow.com/questions/36148778/testing-property-set-by-async-method/36148937#36148937 –

+0

लगता है जैसे आपको अपनी विधि को छोटी इकाइयों में विभाजित करने और व्यक्तिगत रूप से उन इकाइयों में से प्रत्येक का परीक्षण करने की आवश्यकता है। –

उत्तर

5

जब भी मैं एक परीक्षण विधि बनाता हूं जो एसिंक कोड का परीक्षण करने जा रहा है, तो मैं सुनिश्चित करता हूं कि परीक्षण विधि का हस्ताक्षर Async है और कार्य देता है। यह आपको एसिंक शून्य से आने वाले डरावने डेडलॉक से बचने की अनुमति देता है। अब आप परीक्षण विधि के अंदर इंतजार कर सकते हैं।

और जानकारी: https://msdn.microsoft.com/en-us/magazine/dn818493.aspx

उदाहरण:

[TestMethod] 
public async Task myTestMethod() 
{ 
    await MyMethodToTest(); 
} 
+0

हां, यह वास्तव में कुछ भी उपयोगी नहीं करता है क्योंकि परीक्षण परियोजना एक वेबएपीआई सेवा है और गेट स्टेटमेंट में पैरामीटर हैं। '[TestMethod]' async नहीं हो सकता है और इसमें पैरामीटर नहीं हो सकते हैं (यहां तक ​​कि संकलक भी आउटपुट में यह कहता है)। मुझे इसे कठिन तरीके से ढूंढना पड़ा। किसी भी मामले में, यह जानना अच्छा है कि यह समस्या का कारण नहीं है। (bit.ly/1pIdbqU) – MetalPhoenix

-2

आप GetAwaiter और GetResult का उपयोग कर सकते हैं जहां निष्पादन एसिंक्रोनस विधि है जिसे आप परीक्षण करना चाहते हैं।

var mockParam = new Mock<IParam>(); 
var sut = new MyClass(mockParam); 
var result = sut.Execute().GetAwaiter().GetResult(); 

आप यहां अधिक जानकारी प्राप्त कर सकते हैं। https://msdn.microsoft.com/en-us/magazine/dn818493.aspx?f=255&MSPPError=-2147217396। यह संक्षेप में उन अन्य तरीकों का उल्लेख करता है जिनका आप परीक्षण कर सकते हैं लेकिन यह विधि वह है जो आपको सबसे सटीक परिणाम देगी।

+3

यदि आप ऐसा करते हैं तो आप वास्तव में अपने काम को असीमित रूप से नहीं कर रहे हैं, जिसका अर्थ यह है कि यह वास्तविक कोड से भिन्न रूप से कार्य करने जा रहा है, जो एक परीक्षण के लिए एक समस्या है। – Servy

+0

यह इस मामले में है कि async/await मुद्दों का कारण बनता है क्योंकि कुछ तृतीय पक्ष ढांचे एसिंक यूनिट परीक्षण का समर्थन नहीं करते हैं। एक सामान्य परिदृश्य पर async/प्रतीक्षा वही कर सकता है। – MichaelChan

+5

यदि आपका परीक्षण ढांचा एसिंक कोड का समर्थन नहीं करता है (ध्यान दें कि आपको वास्तव में पता नहीं है कि ओपी का ढांचा एसिंक तरीकों का समर्थन नहीं करता है) तो समाधान * एक फ्रेमवर्क प्राप्त करें जो एसिंक विधियों का समर्थन करता है *, यदि आप ' टी, आप बस अपने कोड का परीक्षण नहीं कर रहे हैं, और इसलिए उन परीक्षणों से लाभ नहीं उठाएंगे। – Servy

1

यह Moq ढांचे के लिए एक महान उदाहरण यूज-केस है। उदाहरण के लिए जब आप रिमोट कॉल करने के लिए ध्यान देते हैं, तो उस सेवा को मजाक किया जाना चाहिए। आदर्श रूप से आपको अलग-अलग वैरिएबल पहलुओं को नकल करने की कोशिश करनी चाहिए ताकि आप आसानी से और लगातार आउटपुट के अपेक्षित सेट को सत्यापित करने के लिए इनपुट के ज्ञात सेट प्रदान कर सकें। चूंकि आपने कोई स्रोत कोड प्रदान नहीं किया है, इसलिए मैं कुछ धारणाएं करूंगा - कुछ नमूना कोड और संबंधित यूनिट परीक्षण साझा करें।

public class LoginResult 
{ 
    public string RedirectUrl { get; set; } 
    public string FailureMsg { get; set; } 
    public MonkeyBusiness AuthToken { get; set; } 
} 

[ 
    HttpPost, 
    AllowAnonymous, 
    Route("api/[controller]/login") 
] 
public async Task<LoginResult> Login(
    [FromBody] CredentialsModel credentials, 
    [FromServices] ILogger logger, 
    [FromServices] IAuthenticationModule authentication, 
    [FromServices] IAuthClaimsPrincipalBuiler claimsPrincipalBuilder) 
{ 
    try 
    { 
     var result = 
      await authentication.ExternalAuthenticateAsync(credentials); 

     if (result.IsAuthenticated) 
     { 
      var principal = 
       await claimsPrincipalBuilder.BuildAsync(credentials); 
      await HttpContext.Authentication.SignInAsync("Scheme", principal); 
      return new LoginResult 
      { 
       AuthToken = 
        "Too much source to make up just for stackoverflow, " + 
        "but I hope you now get the point..." 
      }; 
     } 

     return new LoginResult { FailureMsg = "Invalid credentials." }; 
    } 
    catch (Exception ex) 
    { 
     logger.LogError(ex.Message, ex); 
     return new LoginResult { FailureMsg = ex.Message }; 
    } 
} 

तब आपके पास यूनिट परीक्षण हो सकते हैं, जिसमें आप इंटरफेस के विशिष्ट कार्यान्वयन का मज़ाक उड़ाते हैं। इस मामले में आप IAuthenticationModule पर नकल करेंगे और यह सुनिश्चित करने के लिए कई परीक्षण हैं कि रिमोट सर्वर आपके Login तर्क को वांछित/अपेक्षित रूप से प्रबंधित करता है। मॉकिंग async सामान करना बहुत आसान है।

using xUnit; 

[Fact] 
public async Task LoginThrowsAsExpectedTest() 
{ 
    // Arrange  
    var controller = new LoginController(); 
    var loggerMock = new Mock<ILogger>(); 
    var authModuleMock = new Mock<IAuthenticationModule>(); 

    var expectedMessage = "I knew it!";  

    // Setup async methods! 
    authModuleMock.Setup(am => am.ExternalAuthenticateAsync(It.IsAny<CredentialsModel>()) 
        .ThrowsAsync(new Exception(expectedMessage)); 

    // Act 
    var result = 
     await controller.Login(
      new CredentialsModel(), 
      loggerMock.Object, 
      authModuleMock.Object, 
      null); 


    // Assert 
    Assert.Equal(expectedMessage, result.FailureMsg); 
} 

या एक जिसे आप सही ढंग से प्रमाणीकृत करने की अपेक्षा करेंगे।

using xUnit; 

[Fact] 
public async Task LoginHandlesIsNotAuthenticatedTest() 
{ 
    // Arrange  
    var controller = new LoginController(); 
    var loggerMock = new Mock<ILogger>(); 
    var authModuleMock = new Mock<IAuthenticationModule>();   

    var expectedMessage = "Invalid credentials."; 

    // Setup async methods! 
    authModuleMock.Setup(am => am.ExternalAuthenticateAsync(It.IsAny<CredentialsModel>()) 
        .ReturnsAsync(new AuthResult { IsAuthenticated = false });   

    // Act 
    var result = 
     await controller.Login(
      new CredentialsModel(), 
      loggerMock.Object, 
      authModuleMock.Object, 
      null); 


    // Assert 
    Assert.Equal(expectedMessage, result.FailureMsg); 
} 

मुद्दा यह है कि आप अभी भी Moq काफी आसानी से ...

+0

यह समस्या नहीं थी लेकिन यह * बहुत अच्छी जानकारी है और मैं इसे कार्यान्वित कर दूंगा। धन्यवाद! – MetalPhoenix

0

यह बहुत ही विशिष्ट उदाहरण में उपयोग करते हुए async और await इकाई परीक्षण लिख सकते हैं, जानकारी web.config फ़ाइल जब से खींचा जा रहा है यह चलाया जाता है

जब टेस्ट प्रोजेक्ट चलाने का प्रयास करता है, तो "web.config" का संदर्भ बदलता है ताकि परीक्षण प्रोजेक्ट की ऐप सेटिंग्स में कोई कस्टम जानकारी टेस्ट प्रोजेक्ट की ऐप। कॉनफिग फ़ाइल में भी होनी चाहिए। यह व्यवहार कनेक्शन स्ट्रिंग के लिए सुरक्षा प्रथाओं के अनुरूप है और इसलिए आश्चर्य की बात नहीं है।

इस जानकारी को टेस्ट प्रोजेक्ट की ऐप में जोड़ना। कॉनफिग फ़ाइल ने इस मुद्दे को हल किया है।

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