2010-10-12 16 views
6

मैं Reactive Extensions for .NET (Rx) का उपयोग IObservable<T> के रूप में ईवेंट को बेनकाब करने के लिए कर रहा हूं। मैं एक यूनिट टेस्ट बनाना चाहता हूं जहां मैं जोर देता हूं कि एक विशेष घटना निकाल दी जाती है। यहां कक्षा का एक सरलीकृत संस्करण है जिसे मैं परीक्षण करना चाहता हूं:प्रतिक्रियाशील एक्सटेंशन का उपयोग कर किसी ईवेंट के लिए यूनिट परीक्षण

public sealed class ClassUnderTest : IDisposable { 

    Subject<Unit> subject = new Subject<Unit>(); 

    public IObservable<Unit> SomethingHappened { 
    get { return this.subject.AsObservable(); } 
    } 

    public void DoSomething() { 
    this.subject.OnNext(new Unit()); 
    } 

    public void Dispose() { 
    this.subject.OnCompleted(); 
    } 

} 

स्पष्ट रूप से मेरे वास्तविक वर्ग अधिक जटिल हैं। मेरा लक्ष्य यह सत्यापित करना है कि परीक्षा के तहत कक्षा के साथ कुछ क्रियाएं करने से IObservable पर संकेतित घटनाओं का अनुक्रम होता है। सौभाग्य से मैं कक्षाओं को IDisposable लागू करना चाहता हूं और इस विषय पर OnCompleted पर कॉल करना जब ऑब्जेक्ट का निपटारा किया जाता है, तो परीक्षण करना बहुत आसान हो जाता है।

// Arrange 
var classUnderTest = new ClassUnderTest(); 
var eventFired = false; 
classUnderTest.SomethingHappened.Subscribe(_ => eventFired = true); 

// Act 
classUnderTest.DoSomething(); 

// Assert 
Assert.IsTrue(eventFired); 

अगर एक घटना निकाल दिया जाता है नहीं बहुत बुरा है निर्धारित करने के लिए एक चर का उपयोग करना है, लेकिन और अधिक जटिल स्थितियों में इस बात की पुष्टि करने के लिए कि घटनाओं की एक विशेष अनुक्रम हैं चाहते हो सकता है:

यहाँ मैं कैसे परीक्षण है निकाल दिया। क्या यह चर में घटनाओं को रिकॉर्ड किए बिना और फिर चर पर दावा करने के बिना संभव है? IObservable पर दावा करने के लिए एक धाराप्रवाह LINQ- जैसे वाक्यविन्यास का उपयोग करने में सक्षम होने से उम्मीद है कि परीक्षण अधिक पठनीय होगा।

+1

बीटीडब्ल्यू, मुझे लगता है कि एक चर होना पूरी तरह से अच्छा है। उपरोक्त कोड पढ़ने में आसान है, जो सबसे महत्वपूर्ण है। @ पीएल का जवाब अच्छा और सुरुचिपूर्ण है, लेकिन आपको यह समझने के लिए दबाव डालना होगा कि क्या हो रहा है ... शायद इसे एक एक्सटेंशन में बदल दें FailIfNothingHappened() –

+0

@ सर्गी एल्डौखोव: मैं सहमत हूं, लेकिन पीएल के जवाब ने मुझे सीखा कि मैं ' मेरा 'IObservable' कैसे व्यवहार करता है इस बारे में कारण बताएं। और जो हुआ उससे कब्जा करने के लिए चर का उपयोग करके अधिक जटिल परीक्षणों के लिए समझना मुश्किल हो सकता है। साथ ही, जैसा कि आप सुझाव देते हैं, एक एक्सटेंशन बनाना शायद यह समझना आसान हो जाएगा कि क्या हो रहा है। –

+0

मैंने अपने प्रश्न को और अधिक स्पष्ट करने के लिए संपादित किया है जो मैं चाहता हूं। –

उत्तर

11

यह उत्तर आरएक्स के जारी संस्करण 1.0 में अपडेट किया गया है।

आधिकारिक दस्तावेज अभी भी कम है लेकिन एमएसडीएन पर Testing and Debugging Observable Sequences एक अच्छी शुरुआत स्थान है।

परीक्षण कक्षा को ReactiveTest से Microsoft.Reactive.Testing नामस्थान में प्राप्त होना चाहिए। परीक्षण TestScheduler के आसपास आधारित है जो परीक्षण के लिए आभासी समय प्रदान करता है।

TestScheduler.Schedule विधि का उपयोग आभासी समय में कुछ बिंदुओं (टिक) पर गतिविधियों को कतार में करने के लिए किया जा सकता है। परीक्षण TestScheduler.Start द्वारा निष्पादित किया जाता है। यह ITestableObserver<T> लौटाएगा जिसका उपयोग उदाहरण के लिए ReactiveAssert कक्षा का उपयोग करके किया जा सकता है।

public class Fixture : ReactiveTest { 

    public void SomethingHappenedTest() { 
    // Arrange 
    var scheduler = new TestScheduler(); 
    var classUnderTest = new ClassUnderTest(); 

    // Act 
    scheduler.Schedule(TimeSpan.FromTicks(20),() => classUnderTest.DoSomething()); 
    var actual = scheduler.Start(
    () => classUnderTest.SomethingHappened, 
     created: 0, 
     subscribed: 10, 
     disposed: 100 
    ); 

    // Assert 
    var expected = new[] { OnNext(20, new Unit()) }; 
    ReactiveAssert.AreElementsEqual(expected, actual.Messages); 
    } 

} 

TestScheduler.Schedule समय 20 (टिक में मापा जाता है) पर DoSomething के लिए एक कॉल शेड्यूल करने के लिए प्रयोग किया जाता है।

फिर TestScheduler.Start अवलोकन योग्य SomethingHappened पर वास्तविक परीक्षण करने के लिए उपयोग किया जाता है। सब्सक्रिप्शन का जीवनकाल कॉल के तर्कों द्वारा नियंत्रित होता है (फिर से टिकों में मापा जाता है)।

अंत में ReactiveAssert.AreElementsEqual का उपयोग यह सत्यापित करने के लिए किया जाता है कि OnNext को अपेक्षित समय 20 पर कॉल किया गया था।

परीक्षण सत्यापित करता है कि DoSomething पर कॉल करने से तुरंत SomethingHappened दिखाई देता है।

0

अधिक धाराप्रवाह के बारे में निश्चित नहीं है लेकिन यह एक चर को पेश किए बिना चाल करेगा।

var subject = new Subject<Unit>(); 
subject 
    .AsObservable() 
    .Materialize() 
    .Take(1) 
    .Where(n => n.Kind == NotificationKind.OnCompleted) 
    .Subscribe(_ => Assert.Fail()); 

subject.OnNext(new Unit()); 
subject.OnCompleted(); 
+1

मुझे यकीन है कि यह काम नहीं करेगा, सदस्यता में जोर देना अक्सर अजीब चीजें हो रही है और परीक्षण अभी भी गुजर रहा है। –

+0

असफल होने के परीक्षण के लिए आपको ऑननेक्स्ट कॉल के साथ लाइन पर टिप्पणी करनी चाहिए। –

+1

बस एक बिंदु; AsObservable() इस उदाहरण में कोई उद्देश्य नहीं है। –

3

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

जेफरी वान गाग RX टीम से published an article on how to do such kind of testing.

ऊपर परीक्षण, उल्लेख किया दृष्टिकोण का उपयोग कर, इस तरह दिखेगा:

[TestMethod] 
    public void SimpleTest() 
    { 
     var sched = new TestScheduler(); 
     var subject = new Subject<Unit>(); 
     var observable = subject.AsObservable(); 

     var o = sched.CreateHotObservable(
      OnNext(210, new Unit()) 
      ,OnCompleted<Unit>(250) 
      ); 
     var results = sched.Run(() => 
            { 
             o.Subscribe(subject); 
             return observable; 
            }); 
     results.AssertEqual(
      OnNext(210, new Unit()) 
      ,OnCompleted<Unit>(250) 
      ); 
    }: 

संपादित करें: आप भी .OnNext (या किसी अन्य विधि) कॉल कर सकते हैं परोक्ष:

 var o = sched.CreateHotObservable(OnNext(210, new Unit())); 
     var results = sched.Run(() => 
     { 
      o.Subscribe(_ => subject.OnNext(new Unit())); 
      return observable; 
     }); 
     results.AssertEqual(OnNext(210, new Unit())); 

मेरे बिंदु है - सरल स्थितियों में, आप बस आप अपने कहाँ काम कर रहा है ग की जाँच कर रहे फ़े यकीन है कि घटना निकाल दिया जाता है बनाने के लिए (की जरूरत है orrectly)। लेकिन जब आप जटिलता में प्रगति करते हैं, तो आप समय, या समापन, या कुछ और के लिए परीक्षण शुरू करते हैं जिसके लिए वर्चुअल शेड्यूलर की आवश्यकता होती है। लेकिन वर्चुअल शेड्यूलर का उपयोग करके परीक्षण की प्रकृति, "सामान्य" परीक्षणों के विपरीत, पूरे अवलोकन को "एक परमाणु" संचालन का परीक्षण करना है।

तो शायद आपको सड़क के नीचे वर्चुअल शेड्यूलर पर स्विच करना होगा - शुरुआत में इसके साथ क्यों शुरू नहीं करें?

पीएस साथ ही, आपको प्रत्येक टेस्ट केस के लिए एक अलग तर्क का सहारा लेना होगा - f.e. परीक्षण के लिए आपको बहुत अलग अवलोकन होगा कि कुछ ऐसा हुआ जो उसके विपरीत नहीं हुआ।

+2

यह दृष्टिकोण आरएक्स की तरह कुछ परीक्षण करने के लिए बहुत उपयुक्त लगता है। हालांकि, मैं 'ऑननेक्स्ट' कॉल को संश्लेषित नहीं करना चाहता हूं। इसके बजाय मैं यह कहना चाहता हूं कि जिस कक्षा में मैं परीक्षण कर रहा हूं, उसमें विधि के लिए कॉल वास्तव में 'IObservable' पर 'ऑननेक्स्ट' पर कॉल कर रहा है। –

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