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

expect(isTestingInFlutterEasy, isTrue);

Jorge Coca
October 09, 2020

expect(isTestingInFlutterEasy, isTrue);

Flutter is not the new kid on the block anymore; it has been around us for a quite a few years already, helping indie developers, startups and big corporations to bring value to their customers faster than ever, with beautiful experiences that are breathtaking... but how easy is to maintain that software? Is the testing framework as amazing as the UI framework?
Well, SPOILER ALERT: the answer is YES! I've had the pleasure to work on some of the biggest Flutter applications in the market, and testing has been always a key element that helped us to be successful.
In this talk, I'd like to share with you all the things you need to know to test your Flutter application efficiently and in record time, so you can focus on bringing a smile to your customer's face while ensuring that your project maintains an internal high level of quality.

Jorge Coca

October 09, 2020
Tweet

More Decks by Jorge Coca

Other Decks in Technology

Transcript

  1. Types of tes*ng we can do on Flu4er • Unit

    tests for pure Dart only classes
  2. Types of tes*ng we can do on Flu4er • Unit

    tests for pure Dart only classes • Widget tests for isolated widgets
  3. Types of tes*ng we can do on Flu4er • Unit

    tests for pure Dart only classes • Widget tests for isolated widgets • Integra.on tests for the applica6on as a whole
  4. Let's recap for a second • Tests start with main

    • test keyword for each individual unit test
  5. Let's recap for a second • Tests start with main

    • test keyword for each individual unit test • flutter_test as part of the SDK
  6. Let's recap for a second • Tests start with main

    • test keyword for each individual unit test • flutter_test as part of the SDK • Use expect to run an asser;on
  7. Let's recap for a second • Tests start with main

    • test keyword for each individual unit test • flutter_test as part of the SDK • Use expect to run an asser;on • flutter test on CLI to run tests
  8. The test framework offers... • setUpAll runs ONLY ONCE BEFORE

    any test is executed • setUp runs ONCE BEFORE every test
  9. The test framework offers... • setUpAll runs ONLY ONCE BEFORE

    any test is executed • setUp runs ONCE BEFORE every test • tearDown runs ONCE AFTER every test
  10. The test framework offers... • setUpAll runs ONLY ONCE BEFORE

    any test is executed • setUp runs ONCE BEFORE every test • tearDown runs ONCE AFTER every test • tearDownAll runs ONLY ONCE AFTER all test have been executed
  11. Let's recap... • Create a unit tests using the test

    method • Use expect to make asser3ons
  12. Let's recap... • Create a unit tests using the test

    method • Use expect to make asser3ons • Test lifecyle: setUpAll, setUp, tearDown and tearDownAl
  13. Let's recap... • Create a unit tests using the test

    method • Use expect to make asser3ons • Test lifecyle: setUpAll, setUp, tearDown and tearDownAl • Async tests just by using async and await
  14. Let's recap... • Create a unit tests using the test

    method • Use expect to make asser3ons • Test lifecyle: setUpAll, setUp, tearDown and tearDownAl • Async tests just by using async and await • Organize your test file using group
  15. AndroidSummitApp2020App • Takes a GuessGame as a dependency in the

    constructor, but it does nothing with it • No need to mock it
  16. AndroidSummitApp2020App • Takes a GuessGame as a dependency in the

    constructor, but it does nothing with it • No need to mock it • Creates a MaterialApp
  17. AndroidSummitApp2020App • Takes a GuessGame as a dependency in the

    constructor, but it does nothing with it • No need to mock it • Creates a MaterialApp • We can find this widget
  18. AndroidSummitApp2020App • Takes a GuessGame as a dependency in the

    constructor, but it does nothing with it • No need to mock it • Creates a MaterialApp • We can find this widget • Renders the Questionnaire widget immediately
  19. AndroidSummitApp2020App • Takes a GuessGame as a dependency in the

    constructor, but it does nothing with it • No need to mock it • Creates a MaterialApp • We can find this widget • Renders the Questionnaire widget immediately • We can find this widget
  20. Ques%onnaire • Takes a GuessGame as a dependency in the

    constructor that controls the state
  21. Ques%onnaire • Takes a GuessGame as a dependency in the

    constructor that controls the state • We can mock it to control behavior
  22. In widget tests... • We use testWidgets instead of test

    • It provides a WidgetTester to interact with the user interface (UI)
  23. In widget tests... • We use testWidgets instead of test

    • It provides a WidgetTester to interact with the user interface (UI) • We use Finders to locate widgets on the test UI
  24. In widget tests... • We use testWidgets instead of test

    • It provides a WidgetTester to interact with the user interface (UI) • We use Finders to locate widgets on the test UI • There are special matchers: findsOneWidget, findsNWidgets, findsNothing...
  25. Mockito • Since GuessGame is a dependency, we are going

    to mock its behavior using mockito • The syntax is as follows:
  26. Mockito • Since GuessGame is a dependency, we are going

    to mock its behavior using mockito • The syntax is as follows: • We use when(...).thenReturn(...) to control synchronous behavior
  27. Mockito • Since GuessGame is a dependency, we are going

    to mock its behavior using mockito • The syntax is as follows: • We use when(...).thenReturn(...) to control synchronous behavior • We use when(...).thenAnswer(...) to control asynchronous behavior
  28. Why do we mock? • We care about the public

    API contract, not about the implementa6on details
  29. Why do we mock? • We care about the public

    API contract, not about the implementa6on details • It'd be tedious if GuessGame had 100 ques6ons
  30. Why do we mock? • We care about the public

    API contract, not about the implementa6on details • It'd be tedious if GuessGame had 100 ques6ons • We can simulate successes and errors without knowing the internals of our dependencies
  31. Questionnaire renders the question and the final score when the

    game is completed: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ The following assertion was thrown building Text("Test question 1", debugLabel: (englishLike display1 2014).merge(blackMountainView headline4), inherit: false, color: Color(0x8a000000), family: Roboto, size: 34.0, weight: 400, baseline: alphabetic, decoration: TextDecoration.none): No Directionality widget found. RichText widgets require a Directionality widget ancestor. The specific widget that could not find a Directionality ancestor was: RichText The ownership chain for the affected widget is: "RichText ← Text ← Column ← _Question ← Questionnaire ← [root]" Typically, the Directionality widget is introduced by the MaterialApp or WidgetsApp widget at the top of your application widget tree. It determines the ambient reading direction and is used, for example, to determine how to lay out text, how to interpret "start" and "end" values, and to resolve EdgeInsetsDirectional, AlignmentDirectional, and other *Directional objects.
  32. What is going on? • Between ques+on and ques+on there's

    a state change • We need to ask the test system to paint a new frame a;er the state change
  33. What is going on? • Between ques+on and ques+on there's

    a state change • We need to ask the test system to paint a new frame a;er the state change • We use pump and pumpAndSettle for these situa+ons
  34. So far we have... • ✅ Unit tests • ✅

    Widget tests • ❌ Integra/on tests
  35. What do we need to run integra/on tests? • A

    new folder for integra0on test: test_driver
  36. What do we need to run integra/on tests? • A

    new folder for integra0on test: test_driver • A new dart file called app.dart that will contain an "instrumented" version of our app
  37. What do we need to run integra/on tests? • A

    new folder for integra0on test: test_driver • A new dart file called app.dart that will contain an "instrumented" version of our app • A new dart file called app_test.dart that will contain the scripted tests that will exercise our applica0on using FlutterDriver
  38. What do we need to run integra/on tests? • A

    new folder for integra0on test: test_driver • A new dart file called app.dart that will contain an "instrumented" version of our app • A new dart file called app_test.dart that will contain the scripted tests that will exercise our applica0on using FlutterDriver • We cannot use any internal details of our applica0on (blind tests)
  39. So far we have... • ✅ Unit tests • ✅

    Widget tests • ✅ Integra/on tests
  40. It is &me to say "see you later!" • !

    Very Good Ventures • " GDE for Flu3er
  41. It is &me to say "see you later!" • !

    Very Good Ventures • " GDE for Flu3er • # @jcocaramos
  42. It is &me to say "see you later!" • !

    Very Good Ventures • " GDE for Flu3er • # @jcocaramos • $ h3ps:/ /github.com/jorgecoca/androidsummit2020