2012-12-03 48 views

回答

12

如何使用completion匹配器進行測試的完整示例如下。

import 'package:unittest/unittest.dart'; 

class Compute { 
    Future<Map> sumIt(List<int> data) { 
    Completer completer = new Completer(); 
    int sum = 0; 
    data.forEach((i) => sum += i); 
    completer.complete({"value" : sum}); 
    return completer.future; 
    } 
} 

void main() { 
    test("testing a future",() { 
    Compute compute = new Compute();  
    Future<Map> future = compute.sumIt([1, 2, 3]); 
    expect(future, completion(equals({"value" : 6}))); 
    }); 
} 

在此代碼完成之前,單元測試運行器可能無法完成。所以看起來單元測試正確執行。使用Future可能需要較長時間才能完成正確的方法,即使用unittest包中的completion匹配器。

/** 
* Matches a [Future] that completes succesfully with a value that matches 
* [matcher]. Note that this creates an asynchronous expectation. The call to 
* `expect()` that includes this will return immediately and execution will 
* continue. Later, when the future completes, the actual expectation will run. 
* 
* To test that a Future completes with an exception, you can use [throws] and 
* [throwsA]. 
*/ 
Matcher completion(matcher) => new _Completes(wrapMatcher(matcher)); 

有人會試圖做下面這將是單元測試飛鏢返回的未來的不正確的方式。警告:以下是測試期貨的不正確方法。

import 'package:unittest/unittest.dart'; 

class Compute { 
    Future<Map> sumIt(List<int> data) { 
    Completer completer = new Completer(); 
    int sum = 0; 
    data.forEach((i) => sum+=i); 
    completer.complete({"value":sum}); 
    return completer.future; 
    } 
} 

void main() { 
    test("testing a future",() { 
    Compute compute = new Compute(); 
    compute.sumIt([1, 2, 3]).then((Map m) { 
     Expect.equals(true, m.containsKey("value")); 
     Expect.equals(6, m["value"]); 
    }); 
    }); 
} 
+0

很大的幫助,做到這一點!也許你應該把你的答案中的錯誤代碼移到你的問題上。 –

+0

這是什麼不正確? –

+0

哎呀,我明白,第一個代碼段沒有工作...但它的工作原理。忘記我的評論,對不起。 –

14

另一種可能性是使用expectAsync1函數。 工作類似物用於測試的初始不正確的變體將是:

使用expectAsync1爲異步測試
void main() { 
    test("testing a future",() { 
    Compute compute = new Compute(); 
    compute.sumIt([1, 2, 3]).then(expectAsync1((Map m) { 
     Expect.equals(true, m.containsKey("value")); 
     Expect.equals(6, m["value"]); 
    })); 
    }); 
} 

一個優點是它的可組合性。有時測試自然需要幾個連續的異步代碼塊。從mongo_db 樣品測試:

testCursorGetMore(){ 
    var res; 
    Db db = new Db('${DefaultUri}mongo_dart-test'); 
    DbCollection collection; 
    int count = 0; 
    Cursor cursor; 
    db.open().chain(expectAsync1((c){ 
    collection = db.collection('new_big_collection2'); 
    collection.remove(); 
    return db.getLastError(); 
    })).chain(expectAsync1((_){ 
    cursor = new Cursor(db,collection,where.limit(10)); 
    return cursor.each((v){ 
    count++; 
    }); 
    })).chain(expectAsync1((dummy){ 
    expect(count,0); 
    List toInsert = new List(); 
    for (int n=0;n < 1000; n++){ 
     toInsert.add({"a":n}); 
    } 
    collection.insertAll(toInsert); 
    return db.getLastError(); 
    })).chain(expectAsync1((_){ 
    cursor = new Cursor(db,collection,where.limit(10)); 
    return cursor.each((v)=>count++); 
    })).then(expectAsync1((v){ 
    expect(count,1000); 
    expect(cursor.cursorId,0); 
    expect(cursor.state,Cursor.CLOSED); 
    collection.remove(); 
    db.close(); 
    })); 
} 

更新:

和將來輸入單元測試的API進行了更改,因爲問題是最初要求。 現在可以從測試函數返回Future,並且unittest正確執行它,並具有所有異步防護功能。 結合chainthen方法Future現在被合併,爲幾個連續的代碼塊提供了很好的語法測試。在當前版本的mongo_dart中,相同的測試看起來像:

Future testCursorGetMore(){ 
    var res; 
    Db db = new Db('${DefaultUri}mongo_dart-test'); 
    DbCollection collection; 
    int count = 0; 
    Cursor cursor; 
    return db.open().then((c){ 
    collection = db.collection('new_big_collection2'); 
    collection.remove(); 
    return db.getLastError(); 
    }).then((_){ 
    cursor = new Cursor(db,collection,where.limit(10)); 
    return cursor.forEach((v){ 
    count++; 
    }); 
    }).then((dummy){ 
    expect(count,0); 
    List toInsert = new List(); 
    for (int n=0;n < 1000; n++){ 
     toInsert.add({"a":n}); 
    } 
    collection.insertAll(toInsert); 
    return db.getLastError(); 
    }).then((_){ 
    cursor = new Cursor(db,collection,null); 
    return cursor.forEach((v)=>count++); 
    }).then((v){ 
    expect(count,1000); 
    expect(cursor.cursorId,0); 
    expect(cursor.state,State.CLOSED); 
    collection.remove(); 
    return db.close(); 
    }); 
} 
+0

ExpectAsync也是有用的,當你需要測試沒前途的本身,而是一些對象更改的屬性 – Martynas

+0

剛返回的未來也同樣適用於'設置()'和'拆解()'當他們有這樣的測試是執行一些異步代碼直到'setUp()'完成才執行。 –

10

作爲替代方案,這是我一直在做的。它類似於上述問題的答案:

test('get by keys',() { 
    Future future = asyncSetup().then((_) => store.getByKeys(["hello", "dart"])); 
    future.then((values) { 
    expect(values, hasLength(2)); 
    expect(values.contains("world"), true); 
    expect(values.contains("is fun"), true); 
    }); 
    expect(future, completes); 
}); 

我得到未來的引用,並把我所有的期望then調用中的語句。然後,我註冊一個expect(future, completes)以確保它實際完成。

+0

我也喜歡這個例子。我可以通過這種方式看到一個簡單的方法來推銷這個連鎖店。 –

2

請參閱此article中的異步測試部分或expectAsync的API文檔。

下面是一個簡單的例子。請注意,在傳遞給test()返回的閉包之前,必須調用expectAsync()。

import 'package:unittest/unittest.dart'; 

checkProgress() => print('Check progress called.'); 

main() { 
    test('Window timeout test',() { 
    var callback = expectAsync(checkProgress); 
    new Timer(new Duration(milliseconds:100), callback); 
    }); 
} 

另一種方式來等待將來完成時的測試是從傳遞給測試功能關閉返回。從上面鏈接的文章中看到這個例子:

import 'dart:async'; 
import 'package:unittest/unittest.dart'; 

void main() { 
    test('test that time has passed',() { 
    var duration = const Duration(milliseconds: 200); 
    var time = new DateTime.now(); 

    return new Future.delayed(duration).then((_) { 
     var delta = new DateTime.now().difference(time); 

     expect(delta, greaterThanOrEqualTo(duration)); 
    }); 
    }); 
} 
1

對於mockito V 2+有可能與

await untilCalled(mockObject.someMethod())