Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

How to write test

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Test Future

Slide 11

Slide 11 text

Test Future // Test target Future addOneAsync(int num) async => num + 1;

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

Test Future error // Test target Future willThrowException() async => throw Exception();

Slide 16

Slide 16 text

Test Future error void main() { test('Test future error via throwsException matcher', () { expect(willThrowException(), throwsException); }); }

Slide 17

Slide 17 text

Test hidden async operations // Test target class Counter { var value = 9; void addOne() { Future(() => value = value + 1); } }

Slide 18

Slide 18 text

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 タスクはまだ実行されていません

Slide 19

Slide 19 text

Event loop Dartはシングルスレッド言語です。 Event loop で一度に1つのイベントのみを処理します。 https://youtu.be/vl_AaCgudcY?t=165

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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の タスク処理を待ちます

Slide 23

Slide 23 text

Test Stream

Slide 24

Slide 24 text

Test Stream void main() { test('test stream', () { final stream = Stream.fromIterable(['CA', 'Base', 'Next']); expect(stream, emitsInOrder(['CA', 'Base', 'Next', emitsDone])); }); } emitsXxxの命名のような、 他のStreamMatecherもあります

Slide 25

Slide 25 text

Test Stream interactively class Counter { var _value = 0; final _valueStream = StreamController.broadcast(); // Test target Stream get valueStream => _valueStream.stream; void addOne() { _value = _value + 1; _valueStream.add(_value); } }

Slide 26

Slide 26 text

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する時点、値もうすでに 流れていました

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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します

Slide 29

Slide 29 text

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します

Slide 30

Slide 30 text

Recap • Future/Stream のテストには test package が提供する Matcher を使いましょう • 隠された非同期処理をテストするには pumpEventQueue で処理を待ちましょう • 先に expect を呼んで、 後で発生する非同期処理をテストしましょう

Slide 31

Slide 31 text

No content