Как выполнить модульное тестирование, вызывали ли notifyListeners ChangeNotifier в Flutter / Dart? - PullRequest
1 голос
/ 27 января 2020

Я использую пакет provider в нашем приложении и хочу индивидуально протестировать свой класс ChangeNotifier, чтобы иметь простые модульные тесты, проверяющие бизнес-логи c.

Помимо значений ChangeNotifier свойств, я также хочу убедиться, что в определенных случаях (при необходимости) вызывается notifyListeners, в противном случае виджеты, которые используют актуальную информацию из этого класса, не будут обновляться.

В настоящее время я косвенно проверяю, был ли вызван notifyListeners: я использую тот факт, что ChangeNotifier позволяет мне добавить обратный вызов, используя его метод addListener. В обратном вызове, который я добавляю в наш набор тестов, я просто увеличиваю переменную целочисленного счетчика и делаю на это утверждения.

Это правильный способ проверить, вызывает ли мой ChangeNotifier его слушатели? Есть ли более описательный способ тестирования этого?

Вот класс, который я тестирую (упрощенный, поэтому я могу поделиться им в StackOverflow):

import 'package:flutter/foundation.dart';

class ExampleModel extends ChangeNotifier {
  int _value = 0;

  int get value => _value;

  void increment() {
    _value++;
    notifyListeners();
  }
}

и вот как я это тестирую:

import 'package:mobile_app/example_model.dart';
import 'package:test/test.dart';

void main() {
  group('$ExampleModel', () {
    ExampleModel exampleModel;
    int listenerCallCount;

    setUp(() {
      listenerCallCount = 0;
      exampleModel = ExampleModel()
        ..addListener(() {
          listenerCallCount += 1;
        });
    });

    test('increments value and calls listeners', () {
      exampleModel.increment();
      expect(exampleModel.value, 1);
      exampleModel.increment();
      expect(listenerCallCount, 2);
    });

    test('unit tests are independent from each other', () {
      exampleModel.increment();
      expect(exampleModel.value, 1);
      exampleModel.increment();
      expect(listenerCallCount, 2);
    });
  });
}

Кроме того, если вы считаете, что тестирование по-другому было бы лучше, пожалуйста, дайте мне знать, я сейчас работаю в команде соло-разработчиком Flutter, так что это Трудно обнаружить, если я на неправильном пути.

1 Ответ

1 голос
/ 07 февраля 2020

Я столкнулся с той же проблемой. Трудно проверить, была ли вызвана notifyListeners или нет, особенно для async функций. Поэтому я взял вашу идею с помощью listenerCallCount и поместил ее в одну функцию, которую вы можете использовать.

Сначала вам понадобится ChangeNotifier:

class Foo extends ChangeNotifier{
  int _i = 0;
  int get i => _i;
  Future<bool> increment2() async{
    _i++;
    notifyListeners();
    _i++;
    notifyListeners();
    return true;
  }
}

Затем функция:

Future<R> expectNotifyListenerCalls<T extends ChangeNotifier, R>(
    T notifier,
    Future<R> Function() testFunction,
    Function(T) testValue,
    List<dynamic> matcherList) async {
  int i = 0;
  notifier.addListener(() {
    expect(testValue(notifier), matcherList[i]);
    i++;
  });
  final R result = await testFunction();
  expect(i, matcherList.length);
  return result;
}

Аргументы:

  1. ChangeNotifier, который вы хотите проверить.

  2. Функция, которая должна срабатывать notifyListeners (только ссылка на функцию).

  3. Функция в состоянии, которое вы хотите проверить после каждого notifyListeners.

  4. Список ожидаемых значений состояния, которое вы хотите проверить после каждого notifyListeners (порядок важен, а длина должна равняться notifyListeners вызовам).

И вот как проверить ChangeNotifier:

test('should call notifyListeners', () async {
  Foo foo = Foo();

  expect(foo.i, 0);

  bool result = await expectNotifyListenerCalls(
      foo,
      foo.increment2,
      (Foo foo) => foo.i,
      <dynamic>[isA<int>(), 2]);

  expect(result, true);
});
...