2011-05-04 15 views
8

BeginInvoke bir Eylem yönteminde sınamak için bir yöntem arıyorum, çünkü yöntem bir arka plan iş parçacığı üzerinde çalıştığı için gerçekten ne zaman tamamladığını veya geri arama yöntemini çağırdığını bilmenin bir yolu yoktur. Testlerimi beklemeden önce, geri çekilmeden önce testimi bekletmenin bir yolunu arıyorum.Birim Test Nasıl Yapılır StartInvoke bir eylem üzerinde

Aşağıdaki Presenter sınıfında, veri getirildiğinde görünümü güncelleyen arka plan iş parçacığı üzerinde PopulateView öğesini çalıştırdığımı fark edebilirsiniz ve ben Görünüm Özellikleri'nin doğru şekilde başlatıldığını iddia ediyorum.

NUnit ve Moq kullanıyorum.

public class Presenter 
{ 
    private IView _view; 
    private IService _service; 
    public Presenter(IView view, IService service) 
    { 
     _view = view; 
     _service = service; 

     Action action = PopulateView; 
     action.BeginInvoke(PopulateViewCallback, action); 
    } 
    private void PopulateViewCallback(IAsyncResult ar) 
    { 
      try 
      { 
       Action target = (Action)ar.AsyncState; 
       target.EndInvoke(ar); 
      } 
      catch (Exception ex) 
      { 
       Logger.Instance.LogException("Failed to initialize view", ex); 
      } 
    } 

    private void PopulateView() 
    { 
      Thread.Sleep(2000); // Fetch data _service.DoSomeThing() 
      _view.Property1 = "xyz"; 
    } 
} 

cevap

9

Test süresinde istediğiniz davranışı enjekte edebilmeniz için kodunuzu yazın.

public class MethodInvoker 
{ 
    public virtual void InvokeMethod(Action method, Action callback) 
    { 
     method.BeginInvoke(callback, method); 
    } 
} 

Bu sürüm asenkrondir. o zaman uyumsuz olduğunu, Çalışma zamanında

// Inject this dependency 
Invoker.InvokeMethod(PopulateView, PopulateViewCallback); 

:

public class TestInvoker 
{ 
    public IAsyncResult MockResult { get; set; } 

    public override void InvokeMethod(Action method, Action callback) 
    { 
     method(); 
     callback(MockResult); 
    } 
} 

Sonra kod sadece bu kadar değiştirir: test zamanda, sadece bir engelleme versiyonunu yapabilirsiniz. Test süresinde aramayı engeller.

+0

yapmak için kodunuzu yeniden kodlamak zorundasınız, bu konuda iyi düşünmüş ve bunu yeni kod için kullanabilir, ancak birim doğrudan BeginInvoke olarak adlandırılan mevcut kodu test edebilir. – skjagini

+1

Refactor? Orada bağımlılık var; Üniteyi test etmenin tek yolu ya soyutlamak ya da test etmemek. =/ – Tejs

+0

'callback' parametresinin AsyncCallback türünde olması gerekir. Ama teşekkür ederim, bu harika :) – soniiic

2

BeginInvoke() beklemek için kullanabileceğiniz bir IAsyncResult döndürür. Bu durumda _view.Propert1 == "xyz" in -

IAsynchResult ar = action.BeginInvoke(...); 
ar.AsyncWaitHandle.WaitOne(); 
+0

IAsynchResult (ar) 'yı nasıl alabilirim? – skjagini

+0

, BeginInvoke öğesinden dönüş değeridir. Bunu kodda görebilirsiniz. –

+0

Bunu yapıcıdan çağırıyorum ve ünite testlerini yazmak için sınıfın dışından erişim hakkına sahip değilim. – skjagini

0

Sen yöntemler yerine denilen uç sonucu test edildiğinden emin olmak için gerek yoktur.

Bu bir zaman uyumsuz çağrı olduğundan, değerin ayarlandığını periyodik olarak belirten bir döngüye sahip olmanız gerekebilir, ayrıca sınamada bir zaman aşımı ya da kontrol bir zorunluluktur, aksi takdirde testiniz asla başarısız olmaz (yalnızca takılı kalır).

Uyku modunu atlamak için eylemi (PopulateView) engellemeyi düşünebilirsiniz.