Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dartの非同期コードテストについて

 Dartの非同期コードテストについて

817e89f88197980860f1854b74fbee25?s=128

MAO YUFENG

May 27, 2021
Tweet

Transcript

  1. None
  2. 毛昱楓 Mao Yufeng 2019年度 新卒入社 株式会社サイバーエージェント @lcdsmao @lcdsmao

  3. DartのFutureとStreamを用いた 非同期コードをテストするためのアプローチ を紹介します。 Content

  4. How to write test

  5. Add test dependency # pubspec.yaml dev_dependencies: # If this is

    a dart package test: ^1.17.4 # If this is a flutter package flutter_test: sdk: flutter
  6. How to write test // Test target int addOne(int num)

    => num + 1; // Tests are specified using the test() function // Test assertions are made using expect() void main() { test('test add 1', () { expect(addOne(9), 10); // Or using matcher expect(addOne(9), equals(10)); }); }
  7. How to write test // Test target int addOne(int num)

    => num + 1; // Tests are specified using the test() function // Test assertions are made using expect() void main() { test('test add 1', () { expect(addOne(9), 10); // Or using matcher expect(addOne(9), equals(10)); }); }
  8. How to write test // Test target int addOne(int num)

    => num + 1; // Tests are specified using the test() function // Test assertions are made using expect() void main() { test('test add 1', () { expect(addOne(9), 10); // Or using matcher expect(addOne(9), equals(10)); }); }
  9. How to write test // Test target int addOne(int num)

    => num + 1; // Tests are specified using the test() function // Test assertions are made using expect() void main() { test('test add 1', () { expect(addOne(9), 10); // Or using matcher expect(addOne(9), equals(10)); }); }
  10. Test Future

  11. Test Future // Test target Future<int> addOneAsync(int num) async =>

    num + 1;
  12. Test Future void main() { test('Test addOneAsync via completion matcher',

    () { Future<int> data = addOneAsync(9); expect(data, completion(10)); }); test('Test addOneAsync via async/await', () async { int data = await addOneAsync(9); expect(data, 10); }); }
  13. Test Future void main() { test('Test addOneAsync via completion matcher',

    () { Future<int> data = addOneAsync(9); expect(data, completion(10)); }); test('Test addOneAsync via async/await', () async { int data = await addOneAsync(9); expect(data, 10); }); }
  14. Test Future void main() { test('Test addOneAsync via completion matcher',

    () { Future<int> data = addOneAsync(9); expect(data, completion(10)); }); test('Test addOneAsync via async/await', () async { int data = await addOneAsync(9); expect(data, 10); }); }
  15. Test Future error // Test target Future<void> willThrowException() async =>

    throw Exception();
  16. Test Future error void main() { test('Test future error via

    throwsException matcher', () { expect(willThrowException(), throwsException); }); }
  17. Test hidden async operations // Test target class Counter {

    var value = 9; void addOne() { Future(() => value = value + 1); } }
  18. Test hidden async operations void main() { test('test counter addOne',

    () { final counter = Counter(); counter.addOne(); // Assertion will fail, counter.value is still 9. expect(counter.value, 10); }); } Assertion時点に、addOne中のFuture タスクはまだ実行されていません
  19. Event loop Dartはシングルスレッド言語です。 Event loop で一度に1つのイベントのみを処理します。 https://youtu.be/vl_AaCgudcY?t=165

  20. void main() { test('test counter addOne', () { final counter

    = Counter(); counter.addOne(); expect(counter.value, 10); }); } Test hidden async operations
  21. void main() { test('test counter addOne', () async { final

    counter = Counter(); counter.addOne(); // Let event loop handling the addOne task before assertion await Future(() {}); expect(counter.value, 10); }); } Assertionする前に、Event loopの タスク処理を待ちます Test hidden async operations
  22. Test hidden async operations void main() { test('test counter addOne',

    () async { final counter = Counter(); counter.addOne(); // Let event loop handling the addOne task before assertion await pumpEventQueue(); expect(counter.value, 10); }); } Assertionする前に、Event loopの タスク処理を待ちます
  23. Test Stream

  24. Test Stream void main() { test('test stream', () { final

    stream = Stream.fromIterable(['CA', 'Base', 'Next']); expect(stream, emitsInOrder(['CA', 'Base', 'Next', emitsDone])); }); } emitsXxxの命名のような、 他のStreamMatecherもあります
  25. Test Stream interactively class Counter { var _value = 0;

    final _valueStream = StreamController<int>.broadcast(); // Test target Stream<int> get valueStream => _valueStream.stream; void addOne() { _value = _value + 1; _valueStream.add(_value); } }
  26. Test Stream interactively void main() { test('test counter stream', ()

    { final counter = Counter(); counter.addOne(); counter.addOne(); counter.addOne(); // Assertion fail 😵 expect(counter.valueStream, emitsInOrder([1, 2, 3])); }); } Assertionする時点、値もうすでに 流れていました
  27. Test Stream interactively void main() { test('test counter stream', ()

    { final counter = Counter(); // Assert before any opertions expect(counter.valueStream, emitsInOrder([1, 2, 3])); }); }
  28. Test Stream interactively void main() { test('test counter stream', ()

    { final counter = Counter(); // Assert before any opertions expect(counter.valueStream, emitsInOrder([1, 2, 3])); }); } Streamの値が変化する前に Assertionします
  29. Test Stream interactively void main() { test('test counter stream', ()

    { final counter = Counter(); // Assert before any opertions expect(counter.valueStream, emitsInOrder([1, 2, 3])); counter.addOne(); counter.addOne(); counter.addOne(); }); } Streamの値が変化する前に Assertionします
  30. Recap • Future/Stream のテストには test package が提供する Matcher を使いましょう •

    隠された非同期処理をテストするには pumpEventQueue で処理を待ちましょう • 先に expect を呼んで、 後で発生する非同期処理をテストしましょう
  31. None