2010-06-08 21 views
8

Uygulamamın "yapıştırıcı" katmanı için birim testleri yazıyorum ve kullanıcının işlemi erken iptal etmesine izin veren eşzamansız yöntemler için deterministik testler oluşturmada zorluk yaşıyorum.Uzun süren ünite testinde orkestrasyon iptali

Özellikle, bazı zaman uyumsuz yöntemlerde, çağrının iptal edilmesine tepki veren ve tamamlanmadan önce nesnenin uygun durumda olmasını sağlayan bir kodumuz vardır. Bu kod yollarının testlerle karşılandığından emin olmak isterim. aşağıdaki gibi

Bu senaryoda, tipik bir zaman uyumsuz yöntemi örneklendiren Bazı C# sözde kodu:

public void FooAsync(CancellationToken token, Action<FooCompletedEventArgs> callback) 
{ 
    if (token.IsCancellationRequested) DoSomeCleanup0(); 

    // Call the four helper methods, checking for cancellations in between each 
    Exception encounteredException; 
    try 
    { 
     MyDependency.DoExpensiveStuff1(); 
     if (token.IsCancellationRequested) DoSomeCleanup1(); 

     MyDependency.DoExpensiveStuff2(); 
     if (token.IsCancellationRequested) DoSomeCleanup2(); 

     MyDependency.DoExpensiveStuff3(); 
     if (token.IsCancellationRequested) DoSomeCleanup3(); 

     MyDependency.DoExpensiveStuff4(); 
     if (token.IsCancellationRequested) DoSomeCleanup4(); 

    } 
    catch (Exception e) 
    { 
     encounteredException = e; 
    } 

    if (!token.IsCancellationRequested) 
    { 
     var args = new FooCompletedEventArgs(a bunch of params); 
     callback(args); 
    } 
} 

I tutkal tabakası ile sarılır yatan MyDependency işlemleri alay kadar ile gelip içerir olan çözelti ve her birini keyfi bir süre için uyumaya zorluyorlar. Daha sonra async yöntemini çağırıyorum ve birim sınamamıza async isteğini iptal etmeden önce birkaç milisaniye uyumaya anlatıyorum. (Örnek olarak Rhino dalga geçer kullanarak) böyle

şey: bir birim testinde Thread.Sleep kullanarak kusacak beni yapar olmasından Kenara

[TestMethod] 
public void FooAsyncTest_CancelAfter2() 
{ 
    // arrange 
    var myDependency = MockRepository.GenerateStub<IMyDependency>(); 

    // Set these stubs up to take a little bit of time each so we can orcestrate the cancels 
    myDependency.Stub(x => x.DoExpensiveStuff1()).WhenCalled(x => Thread.Sleep(100)); 
    myDependency.Stub(x => x.DoExpensiveStuff2()).WhenCalled(x => Thread.Sleep(100)); 
    myDependency.Stub(x => x.DoExpensiveStuff3()).WhenCalled(x => Thread.Sleep(100)); 
    myDependency.Stub(x => x.DoExpensiveStuff4()).WhenCalled(x => Thread.Sleep(100)); 

    // act 
    var target = new FooClass(myDependency); 

    CancellationTokenSource cts = new CancellationTokenSource(); 
    bool wasCancelled = false; 

    target.FooAsync(
     cts.Token, 
     args => 
     { 
     wasCancelled = args.IsCancelled; 
     // Some other code to manipulate FooCompletedEventArgs 
     }); 

    // sleep long enough for two operations to complete, then cancel 
    Thread.Sleep(250); 
    cts.Cancel(); 

    // Some code to ensure the async call completes goes here 

    //assert 
    Assert.IsTrue(wasCancelled); 
    // Other assertions to validate state of target go here 
} 

, daha büyük bir sorun bazen böyle testler başarısız olmasıdır Eğer önemli bir yük altında olsaydı bizim yapı sunucusunda. Async çağrısı çok uzağa gider ve iptal çok geç olur.

Böyle uzun çalışma işlemleri için daha güvenilir bir şekilde birim testi iptal mantığı sağlayan herhangi biri var mı? Herhangi bir fikir takdir edilecektir.

cevap

5

Eşzamansız bir şekilde zaman uyumsuz davranışı "benzetmek" için alay kullanmaya çalışırdım.

myDependency.Stub(x => x.DoExpensiveStuff1()); 
myDependency.Stub(x => x.DoExpensiveStuff2()); 
myDependency.Stub(x => x.DoExpensiveStuff3()).WhenCalled(x => cts.Cancel()); 
myDependency.Stub(x => x.DoExpensiveStuff4()); 

şifrenizin bakış açısıyla bu sanki görünecektir: Yerine

myDependency.Stub(x => x.DoExpensiveStuff1()).WhenCalled(x => Thread.Sleep(100)); 

kullanarak ve sonra milisaniye ne olursa olsun sayısı içinde iptal bayrak ayarlamasını, sadece geri arama parçası olarak kuracak çağrı sırasında iptal edildi.

+0

Bu son derece umut verici görünüyor. Bu öğleden sonra deneyeceğim ve geri bildireceğim. –

+0

Güzel çalıştı. Yardım ettiğin için teşekkür ederim! –

1

Uzun süren işlemlerin her biri, çalışmaya başladıklarında bir olayı tetiklemelidir.

Bu olayı ünite testine takın. Bu, olayların gelecekte faydalı olabileceği potansiyeli ile belirleyici sonuçlar verir.

İlgili konular