2012-12-03 11 views

Odpowiedz

12

Pełny przykład sposobu testowania z użyciem macierzy completion jest następujący.

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}))); 
    }); 
} 

Uruchomiony test jednostki może nie zakończyć się przed ukończeniem tego kodu. Wydaje się więc, że test jednostkowy został wykonany poprawnie. Z Future s ukończenie prawidłowego sposobu może zająć więcej czasu, ponieważ należy użyć wycinarki completion dostępnej w pakiecie unittest.

Można by pokusić się na następujące rzeczy, które byłyby niewłaściwym sposobem testowania jednostki zwróconej Przyszłości w lotkę. OSTRZEŻENIE: poniżej jest nieprawidłowy sposób testowania kontraktów futures.

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

Wielkiej! Być może powinieneś przenieść nieprawidłowy kod z odpowiedzi na swoje pytanie. –

+0

Co było w tym błędne? –

+0

Ups, zrozumiałem, że pierwszy fragment kodu nie zadziałał ... Ale działa. Zapomnij o moim komentarzu, przepraszam. –

14

Inną możliwością jest użycie funkcji expectAsync1. analogowy roboczy do początkowego błędnego wariantu testu byłoby:

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"]); 
    })); 
    }); 
} 

Zaletą w użyciu expectAsync1 do testowania asynchronicznym jest jego composability. Czasami testy naturalnie wymagają kilku kolejnych asynchronicznych bloków kodu. badanie próbki z 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(); 
    })); 
} 

Aktualizacja:

Zarówno Future i unittest API zostały zmienione, ponieważ pytanie było początkowo poprosił. Teraz jest możliwe, po prostu powrócić Future z funkcji testu i unittest poprawnie wykonane z wszystkimi asynchroniczne funkcje chronione. W połączeniu z faktem, że chain i then metody Future są teraz scalane, które zapewniają dobrą składnię do testów z kilkoma sekwencyjnymi blokami kodu. W obecnej wersji mongo_dart ten sam test wygląda następująco:

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 jest również przydatny, gdy trzeba przetestować nie samą przyszłość, ale niektóre zmiany właściwości obiektu – Martynas

+0

Właśnie zwrócenie przyszłości działa również dla 'setUp()' i 'tearDown()', gdy muszą wykonać jakiś kod asynchroniczny, więc testy są nie wykonywane, dopóki nie zakończy się działanie 'setUp()'. –

10

Alternatywnie, oto, co robiłem. Jest to podobne do powyższych odpowiedzi:

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); 
}); 

uzyskać odniesienie do przyszłości, i umieścić wszystkie moje oczekiwać oświadczenia wewnątrz zaproszenia then. Następnie rejestruję numer expect(future, completes), aby się upewnić, że faktycznie się zakończył.

+0

Podoba mi się również ten przykład. Widziałem w ten sposób łatwą drogę do przyszłości w łańcuchu. –

2

Zobacz rozdział dotyczący testów asynchronicznych w tym article lub dokumentację API dla expectAsync.

Poniżej znajduje się krótki przykład. Zauważ, że funkcja expectAsync() musi zostać wywołana, zanim zamknięcie zostanie przekazane do funkcji test().

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); 
    }); 
} 

Innym sposobem czekać na przyszłość, aby zakończyć podczas testu jest przywrócenie go z zamknięciem przekazany do funkcji testowej.Zobacz ten przykład z artykułu związanego powyżej.

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

Dla mockito v 2+ Istnieje możliwość, aby to zrobić z pomocą

await untilCalled(mockObject.someMethod())