2010-03-22 11 views
8

मेरे पास एक ऐसी विधि है जिसमें एक ऐसी विधि है जो एक परिणाम ऑब्जेक्ट देता है जिसमें फ़ंक प्रकार की संपत्ति होती है।मैं एक सी # फ़ंक्शन का परीक्षण कैसे करूं जो एक Func <something> देता है?

class Result { 
    public Func<Result> NextAction { get; set; } 
} 

मैं इस Func की सामग्री के संबंध में एक इकाई परीक्षण दावा कैसे लिखूं? निम्नलिखित स्पष्ट रूप से काम नहीं करता है, क्योंकि संकलक लैम्ब्डा के लिए दो अलग अलग तरीकों उत्पन्न करता है:

// Arrange 
ListController controller = new ListController(domain); 
// Act 
Result actual = controller.DefaultAction(); 
// Assert 
Func<Result> expected =() => new ProductsController(domain).ListAction(); 
Assert.That(actual.NextAction, Is.EqualTo(expected)); 

मेरा अनुमान है कि मैं बजाय अभिव्यक्ति के पेड़ का उपयोग करके ऐसा कर सकते हैं, लेकिन ... वहाँ एक रास्ता से बचने के लिए है ऐसा करने से? मैं NUnit 2.5 का उपयोग कर रहा हूँ।

संपादित करें: परिणाम वस्तु में कोई अन्य पहचान फ़ील्ड नहीं हैं। यह वर्तमान वस्तु/विधि में किए गए निर्णय के आधार पर अगली वस्तु/विधि का आह्वान करने का एक तरीका है।

उत्तर

0

वैसे ऐसा लगता है कि Func की सामग्री का परीक्षण इकाई इकाई परीक्षण की सामान्य सीमा से परे है। एक Func संकलित कोड का प्रतिनिधित्व करता है, और इसलिए एमएसआईएल को पार्स करने के बिना आगे निरीक्षण नहीं किया जा सकता है। इस स्थिति में, इसलिए प्रतिनिधियों और तत्काल प्रकारों (जैसे नाथन बाउच द्वारा सुझाए गए), या इसके बजाय अभिव्यक्ति पेड़ का उपयोग करने के लिए आवश्यक है।

मेरे अभिव्यक्ति पेड़ के नीचे बराबर:

class Result { 
    public Expression<Func<Result>> NextAction { get; set; } 
} 
इकाई परीक्षण के साथ

इस प्रकार है:

// Arrange 
ListController controller = new ListController(domain); 
// Act 
Result actual = controller.DefaultAction(); 
// Assert 
MethodCallExpression methodExpr = (MethodCallExpression)actual.NextAction.Body; 
NewExpression newExpr = (NewExpression)methodExpr.Object; 
Assert.That(newExpr.Type, Is.EqualTo(typeof(ProductsController))); 
Assert.That(methodExpr.Method.Name, Is.EqualTo("ListAction")); 

नोट इस परीक्षण के लिए कुछ निहित कमजोरी है कि वहाँ के रूप में यह अभिव्यक्ति की संरचना का अर्थ है, साथ ही इसके व्यवहार।

2

क्यों Func का आह्वान न करें और लौटाए गए मूल्यों की तुलना करें?

var actualValue = actual.NextAction(); 
var expectedValue = expected(); 
Assert.That(actualValue, Is.EqualTo(expectedValue)); 

संपादित करें: मुझे लगता है कि परिणाम वर्ग की कोई पहचान नहीं है। मुझे लगता है कि आपके पास परिणाम वर्ग में कुछ अन्य फ़ील्ड हैं जो परिणाम की पहचान को परिभाषित करते हैं और यह निर्धारित करने के लिए उपयोग किया जा सकता है कि दो परिणाम बराबर हैं या नहीं।

+0

क्योंकि फंक एक ही समस्या के साथ एक और परिणाम वस्तु देता है! – goofballLogic

+0

फिर आपको परिणाम को पहचानने और उस – Marek

+0

के आधार पर समानता निर्धारित करने की आवश्यकता है जो फ़ंक के इरादे का वर्णन करने वाली मनमानी स्ट्रिंग की तरह है? – goofballLogic

0

यदि आप Func<Result> हमेशा एक ही परिणाम लौटते हैं तो आप परीक्षण कर सकते हैं कि फ़ंक्शन द्वारा कौन सी ऑब्जेक्ट लौटा दी गई है।

+0

दुर्भाग्यवश, Func एक परिणाम देता है जिसमें केवल एक और Func goofballLogic

2

मुझे लैम्ब्डा के अंदर देखने के लिए एक आसान तरीका पता नहीं है (जैसा आपने कहा था अभिव्यक्ति पेड़ों का उपयोग करने के अलावा) लेकिन प्रतिनिधियों की तुलना करना संभव है यदि उन्हें method group असाइन किया गया हो।

var result1 = new Result { 
    NextAction = new ProductsController(domain).ListAction }; 
var result2 = new Result { 
    NextAction = new ProductsController(domain).ListAction }; 

//objects are different 
Assert.That(result1, Is.Not.EqualTo(result2)); 

//delegates are different 
Assert.That(result1.NextAction, Is.Not.EqualTo(result2.NextAction)); 

//methods are the same 
Assert.That(result1.NextAction.Method, Is.EqualTo(result2.NextAction.Method)); 

उपरोक्त उदाहरण काम नहीं करता है यदि आप विभिन्न तरीकों से संकलित होने के बाद लैम्बडा का उपयोग करते हैं।

+0

है हाँ यह ईवेंट पंजीकरण, या किसी अन्य प्रतिनिधि उपयोग के लिए परीक्षण की तरह है। हालांकि यह सबसे अच्छा समझौता हो सकता है, मूल उद्देश्य आवेदक का आह्वान करने के हिस्से के रूप में ProductsController के त्वरण को शामिल करना था। – goofballLogic

0

यदि मैं इस मुद्दे को सही ढंग से समझता हूं तो अगला एक्शन में एक अलग लैम्ब्डा कार्यान्वयन हो सकता है या नहीं, जिसे परीक्षण की आवश्यकता है।

नीचे दिए गए उदाहरण में मैं आईएल बाइट्स के तरीकों की तुलना करता हूं। प्रतिबिंब का उपयोग करके, एक सरणी में शरीर से विधि जानकारी और आईएल बाइट प्राप्त करें। यदि बाइट एरे मैच मिलते हैं, तो लैम्ब्डा एक जैसा होता है।

ऐसी कई स्थितियां हैं जो यह संभाल नहीं लेती हैं, लेकिन यदि यह दो लैम्ब्डा की तुलना करने का सिर्फ सवाल है जो बिल्कुल वही होना चाहिए, तो यह काम करेगा।क्षमा करें यह एमएसटीएस्ट में है :)

using System.Reflection; 
.... 


    [TestClass] 
    public class Testing 
    { 
     [TestMethod] 
     public void Results_lambdas_match() 
     { 
      // Arrange 
      ListController testClass = new ListController(); 
      Func<Result> expected = () => new ProductsController().ListAction(); 
      Result actual; 
      byte[ ] actualMethodBytes; 
      byte[ ] expectedMethodBytes; 

      // Act 
      actual = testClass.DefaultAction(); 

      // Assert 
      actualMethodBytes = actual.NextAction. 
       Method.GetMethodBody().GetILAsByteArray(); 
      expectedMethodBytes = expected. 
       Method.GetMethodBody().GetILAsByteArray(); 

      // Test that the arrays are the same, more rigorous check really should 
      // be done .. but this is an example :) 
      for (int count=0; count < actualMethodBytes.Length; count++) 
      { 
       if (actualMethodBytes[ count ] != expectedMethodBytes[ count ]) 
        throw new AssertFailedException(
         "Method implementations are not the same"); 
      } 
     } 
     [TestMethod] 
     public void Results_lambdas_do_not_match() 
     { 
      // Arrange 
      ListController testClass = new ListController(); 
      Func<Result> expected = () => new OtherController().ListAction(); 
      Result actual; 
      byte[ ] actualMethodBytes; 
      byte[ ] expectedMethodBytes; 
      int count=0; 

      // Act 
      actual = testClass.DefaultAction(); 

      // Assert 
      actualMethodBytes = actual.NextAction. 
       Method.GetMethodBody().GetILAsByteArray(); 
      expectedMethodBytes = expected. 
       Method.GetMethodBody().GetILAsByteArray(); 

      // Test that the arrays aren't the same, more checking really should 
      // be done .. but this is an example :) 
      for (; count < actualMethodBytes.Length; count++) 
      { 
       if (actualMethodBytes[ count ] != expectedMethodBytes[ count ]) 
        break; 
      } 
      if ((count + 1 == actualMethodBytes.Length) 
       && (actualMethodBytes.Length == expectedMethodBytes.Length)) 
       throw new AssertFailedException(
        "Method implementations are the same, they should NOT be."); 
     } 

     public class Result 
     { 
      public Func<Result> NextAction { get; set; } 
     } 
     public class ListController 
     { 
      public Result DefaultAction() 
      { 
       Result result = new Result(); 
       result.NextAction = () => new ProductsController().ListAction(); 

       return result; 
      } 
     } 
     public class ProductsController 
     { 
      public Result ListAction() { return null; } 
     } 
     public class OtherController 
     { 
      public Result ListAction() { return null; } 
     } 
    } 
+0

हां, यह एक संभावना हो सकती है। यह वास्तव में काम कर सकता है, सिवाय इसके कि कोड "डोमेन" पैरामीटर में उत्पाद नियंत्रक के निर्माता को गुजर रहा है जो विभिन्न आईएल को हल करता है। मेरा मानना ​​है कि यह संकलित लैम्ब्डा अभिव्यक्ति की मेजबानी के लिए बनाई गई कक्षा के कारण है। – goofballLogic

+0

इसके आस-पास एक तरीका चल रहा कोड से सही आईएल बाइट कोड 'कैप्चर' करना होगा और बस उससे मिलान करना होगा। परीक्षा परीक्षण की जा रही स्थितियों के लिए बहुत विशिष्ट हो जाएगी, लेकिन काम करेगा। यदि आपके पास उस विशिष्ट स्थिति के लिए एक परीक्षण है, तो यह बुरा नहीं है, लेकिन मैं उनमें से बहुत कुछ नहीं चाहता। – MarcLawrence

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