簡體   English   中英

Rx和異步nunit測試

[英]Rx and async nunit test

我正在嘗試為項目創建異步單元測試,但無法理解如何等待異步主題完成:

    [Test]
    public async void MicroTest()
    {
        var value = 2;

        var first = new AsyncSubject<int>();
        var second = new AsyncSubject<int>();

        first.Subscribe(_ =>
        {
            value = _;
            second.OnCompleted();
        });

        first.OnNext(1);

        // how to wait for the second subject to complete?

        Assert.AreEqual(value, 1);
    }

此測試的同步版本運行良好:

    [Test]
    public void MicroTest()
    {
        var value = 2;

        var first = new Subject<int>();
        var second = new Subject<int>();

        first.Subscribe(_ =>
        {
            value = _;
            second.OnCompleted();
        });

        first.OnNext(1);

        Assert.AreEqual(value, 1);
    }

AsyncSubject與Subject

首先,值得指出AsyncSubject<T>不是Subject<T>的異步版本。 兩者實際上都是自由線程*(見腳注)。

AsyncSubjectSubject一個特化,旨在用於建模異步完成並返回單個結果的操作。 它有兩個值得注意的特點:

  • 僅發布最后一個結果
  • 結果被緩存,並且在完成后訂閱的觀察者可以使用。

它在內部用於各種地方,包括在TaskTask<T>上定義的ToObservable()擴展方法。

測試的問題

Recall AsyncSubject<T>僅返回收到的最終結果。 它通過等待OnCompleted()來實現這一點,因此它知道最終結果是什么。 因為你不叫OnCompleted()first測試是有缺陷的OnNext()處理程序-將永遠不會被調用-在你的訂閱調用傳遞lambda函數。

此外,它是無效的調用OnNext()上的至少一次AsyncSubject<T>所以當調用await second; 如果你還沒有這樣做,你將得到一個InvalidOperationException

如果你按如下方式編寫測試,一切都很好:

[Test]
public async void MicroTest()
{
    var value = 2;

    var first = new AsyncSubject<int>();
    var second = new AsyncSubject<int>();

    first.Subscribe(_ =>
    {
        // won't be called until an OnCompleted() has
        // been invoked on first
        value = _;
        // you must send *some* value to second
        second.OnNext(_);
        second.OnCompleted();
    });

    first.OnNext(1);
    // you must do this for OnNext handler to be called
    first.OnCompleted(); 

    // how to wait for the second subject to complete
    await second;

    Assert.AreEqual(value, 1);
}

關於異步測試

作為一般規則,我會避免編寫可以永遠等待的異步測試。 當它導致構建服務器上的資源耗盡時,這尤其令人討厭。 使用某種超時,例如:

await second.Timeout(TimeSpan.FromSeconds(1));

無需處理異常,因為這足以使測試失敗。

**我從COM詞典中借用了這個術語。 從這個意義上講,我的意思是,與大多數Rx框架組件一樣,它們通常會在您調用其方法的任何線程上運行。 自由線程並不一定意味着完全線程安全。 特別是,與AsyncSubject<T>Subject<T>不會保護您免受Rx語法沖突的影響,即對OnNext進行重疊調用。 使用Subject.SynchronizeObservable.Synchronize進行此保護。*

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM