Guia minimalista para testes no Flutter — Parte 4 Pacotes úteis

Tempo de leitura: 5 minutes

Esta é a última parte da série Flutter Testing, eu só queria mostrar a você pacotes úteis para testes que você vai adorar!

 

Golden Toolkit

golden_toolkit é um kit de ferramentas para testes de ouro que tornam seus testes muito mais fáceis e legíveis, e também é feito pelo eBay!

Exemplo

testGoldens('Weather types should look correct', (tester) async {
  final builder = GoldenBuilder.grid(
      columns:2,
      widthToHeightRatio: 1,
    )..addScenario('Sunny', WeatherCard(Weather.sunny))
     ..addScenario('Cloudy', WeatherCard(Weather.cloudy))
     ..addScenario('Raining', WeatherCard(Weather.rain))
     ..addScenario('Cold', WeatherCard(Weather.cold));
  await tester.pumpWidgetBuilder(builder.build());
  await screenMatchesGolden(tester, 'weather_types_grid');
});

 

Alchemist

alchemist também é um pacote de teste de ouro inspirado no golden_toolkit, mas feito por equipes betterment e Very Good Ventures 🦄 !

Exemplo

goldenTest(
  'renders correctly',
  fileName: 'list_tile',
  builder: () => GoldenTestGroup(
    scenarioConstraints: const BoxConstraints(maxWidth: 600),
    children: [
      GoldenTestScenario(
        name: 'with title',
        child: ListTile(
          title: Text('ListTile.title'),
        ),
      ),
      GoldenTestScenario(
        name: 'with title and subtitle',
        child: ListTile(
          title: Text('ListTile.title'),
          subtitle: Text('ListTile.subtitle'),
        ),
      ),
      GoldenTestScenario(
        name: 'with trailing icon',
        child: ListTile(
          title: Text('ListTile.title'),
          trailing: Icon(Icons.chevron_right_rounded),
        ),
      ),
    ],
  ),
);

 

Patrol

patrol é uma estrutura de teste de interface do usuário que elimina as limitações de flutter_test, integration_test e flutter_driver.
Ele nos permite escrever testes mais legíveis, fáceis e avançados.

Exemplo

patrolTest(
    nativeAutomation: true,
    'counter state is the same after going to Home and going back',
    ($) async {
      await $.pumpWidgetAndSettle(const MyApp());

      await $(FloatingActionButton).tap();
      expect($(#counterText).text, '1');

      await $.native.pressHome();
      await $.native.pressDoubleRecentApps();

      expect($(#counterText).text, '1');
      await $(FloatingActionButton).tap();
      expect($(#counterText).text, '2');

      await $.native.openNotifications();
      await $.native.pressBack();
    },
  );

 

Fluttium

fluttium é uma estrutura de teste de fluxo de usuário que nos permite escrever testes usando mágica! pelo autor dos pacotes flame e umbra!

 

 

Honey

honey é um pacote que nos ajuda a escrever facilmente testes de ponta a ponta, feito por ClickUp e Simon (o autor de Hive e Isar).

 

Convenient Test

convenient_test, nos ajuda a gerenciar nossos testes usando uma bela GUI, do autor de flutter_portal

 

 

Spec

spec é um framework de testes simplificado que torna os testes mais fáceis e seguros, feito pela invertase!

import 'package:spec/spec.dart';

void main() {
  test('future example', () async {
    final future = Future.value(42);
    expect(future).toEqual(future);
    await expect(future).completion.toEqual(42);
    await expect(future).throws.isArgumentError();
  });

  test('stream example', () async {
    final stream = Stream.value(42);
    await expect(stream).emits.toEqual(42);
    await expect(stream).emits.isNull();
    await expect(stream).emits.not.isNull();
    await expect(stream).emitsError.isArgumentError();
  });

  test('function example', () {
    void throwsFn() => throw Error();
    expect(throwsFn).returnsNormally();
    expect(throwsFn).throws.isArgumentError();
  });
}

 

Mockingjay

mockingjay torna os testes de navegação ainda mais fáceis! por Very Good Ventures 🦄

Mocktail

Uma biblioteca mocking sem geração de código, do autor do bloco!

class MockCat extends Mock implements Cat {}
class Cat {...}
final cat = MockCat();

 

Mockito

mockito é uma biblioteca mocking com geração de código, feita pela equipe dart!

@GenerateMocks([Cat])
class Cat {...}
final cat = MockCat();

 

Faker

faker nos dá valores falsos para adicionar aos nossos objetos de teste.

Exemplo

final faker = Faker();
faker.internet.email(); // francisco_lebsack@buckridge.com
faker.internet.userName(); // fiona-ward
faker.person.name(); // Fiona Ward

 

Flutter Gherkin

flutter_gherkin nos permite dar valores e personalizar os testes usando BDD/Gherkin.

Feature: Hello World
  Hello World feature test

  Scenario: Check App Title And Content
    Given I expect the "firstTabTitle" to be "Jeresy Cool!"
    Then I expect the "textField" to be "Hello, Jersey!"

  Scenario: Check App Title When Switch Page
    Given I go to second page
    Then I expect second page title to be "Jersey Second Tab"
    When I go to landing page
    Then I expect landing page title to be "Jeresy Cool!"
Feature: Counter
  Check counter is correct after tap add button

  Scenario: Check Counter Number
    Given I expect the "counterTextField" to be "0"
    When I tap the "addBtn" button 20 times
    Then I expect the "counterTextField" to be "20"

 

 

BDD Widget Test (BDD to Dart)

bdd_widget_test nos ajuda a gerar testes apenas usando BDD!

Exemplo

Feature: Counter
Background:
    Given the app is running
After:
    And I do not see {'surprise'} text
Scenario: Initial counter value is 0
    Then I see {'0'} text
Scenario: Add button increments the counter
    When I tap {Icons.add} icon
    Then I see {'1'} text
Scenario Outline: Plus button increases the counter
    Given the app is running
    When I tap {Icons.add} icon <times> times
    Then I see <result> text
Examples:
      | times | result |
      |    0  |   '0'  |
      |    1  |   '1'  |
      |   42  |  '42'  |

Para

Future<void> bddSetUp(WidgetTester tester) async {
  await theAppIsRunning(tester);
}
Future<void> bddTearDown(WidgetTester tester) async {
  await iDoNotSeeText(tester, 'surprise');
}
group('''Counter''', () {
  testWidgets('''Initial counter value is 0''', (tester) async {
    try {
      await bddSetUp(tester);
      await iSeeText(tester, '0');
    } finally {
      await bddTearDown(tester);
    }
  });
  testWidgets('''Add button increments the counter''', (tester) async {
    try {
      await bddSetUp(tester);
      await iTapIcon(tester, Icons.add);
      await iSeeText(tester, '1');
    } finally {
      await bddTearDown(tester);
    }
  });
  testWidgets('''Outline: Plus button increases the counter (0, '0')''', (tester) async {
    try {
      await bddSetUp(tester);
      await theAppIsRunning(tester);
      await iTapIconTimes(tester, Icons.add, 0);
      await iSeeText(tester, '0');
    } finally {
      await bddTearDown(tester);
    }
  });
  testWidgets('''Outline: Plus button increases the counter (1, '1')''', (tester) async {
    try {
      await bddSetUp(tester);
      await theAppIsRunning(tester);
      await iTapIconTimes(tester, Icons.add, 1);
      await iSeeText(tester, '1');
    } finally {
      await bddTearDown(tester);
    }
  });
  testWidgets('''Outline: Plus button increases the counter (42, '42')''', (tester) async {
    try {
      await bddSetUp(tester);
      await theAppIsRunning(tester);
      await iTapIconTimes(tester, Icons.add, 42);
      await iSeeText(tester, '42');
    } finally {
      await bddTearDown(tester);
    }
  });
});

 

BDD Framework (Dart to BDD)

bdd_framework basicamente, converte seus códigos Dart em recursos BDD

Exemplo

final feature = BddFeature('Buying amount');
    
Bdd(feature)
  .scenario('Buying amount for stock orders, with zero fees.')
  //
  .given('The user has 120 dollars.')
  .and('IBM bid-price is 3 dollars, ask-price is 10.')
  .and('Fees are zero.')
  //
  .when('The user opens the order.')
  //
  .then('The buying amount is 12 shares.')
  .and('It costs 120 dollars.')
  //      
  .run((ctx) async {
    // Given:
    setCashBalance(120);         
    setQuote(IBM, bid: 3, ask: 10);
    setFees(0);         
    // When:
    var buyingAmount = openOrder(IBM);
    // Then:
    expect(buyingAmount.shares, 12);         
    expect(buyingAmount.dollars, 120);
  });

Saida

Feature: Buying amount

  Scenario: Buying amount for stock orders, with zero fees.
    Given the user has 120 dollars.
    And IBM bid-price is 3 dollars, ask-price is 10.
    And fees are zero.
    When the user opens the order.
    Then the buying amount is 12 shares.
    And it costs 120 dollars.

 

 

Obrigado por ler!