Полный гайд по тестированию на Flutter. Часть 4: продвинутое модульное тестирование

import 'package:shared_preferences/shared_preferences.dart';


class LoginViewModel {

  final SharedPreferences sharedPreferences;


  LoginViewModel({

    required this.sharedPreferences,

  });


  final Map<String, String?> _cache = {};


  bool login(String email, String password) {

    if (_cache.containsKey(email)) {

      return password == _cache[email];

    }


    final storedPassword = sharedPreferences.getString(email);

    _cache[email] = storedPassword;


    return password == storedPassword;

  }

}

(Аннотация @visibleForTesting)

final Map<String, String?> _cache = {};


// Expose this method for testing purposes to set values in _cache

@visibleForTesting

void putToCache(String email, String? password) {

  _cache[email] = password;

}

group('login', () {

  test('login should return true when the cache contains the password input even when the password is incorrect', () {

    // Arrange

    final mockSharedPreferences = MockSharedPreferences();

    final loginViewModel = LoginViewModel(

      sharedPreferences: mockSharedPreferences,

    );

    String email = 'ntminh@gmail.com';

    String password = 'abc';


    loginViewModel.putToCache(email, 'abc'); // NEW


    // Stubbing

    when(() => mockSharedPreferences.getString(email))

        .thenReturn('123456');


    // Act

    final result = loginViewModel.login(email, password);


    // Assert

    expect(result, true);

  });


  test('login should return false when the cache does not contain the password input and the password is incorrect', () {

    // Arrange

    final mockSharedPreferences = MockSharedPreferences();

    final loginViewModel = LoginViewModel(

      sharedPreferences: mockSharedPreferences,

    );

    String email = 'ntminh@gmail.com';

    String password = 'abc';


    // Stubbing

    when(() => mockSharedPreferences.getString(email))

        .thenReturn('123456');


    // Act

    final result = loginViewModel.login(email, password);


    // Assert

    expect(result, false);

  });

});

void main() {

  late MockSharedPreferences mockSharedPreferences;

  late LoginViewModel loginViewModel;


  setUp(() {

    mockSharedPreferences = MockSharedPreferences();

    loginViewModel = LoginViewModel(

      sharedPreferences: mockSharedPreferences,

    );

  });


  ...

}

(Функции setUp, tearDown, setUpAll, tearDownAll)

setUp (initialization) -> test case 1 -> setUp (re-initialization) -> test case 2

setUpAll(() async {

  await Isar.initializeIsarCore(download: true);

  isar = await Isar.open([JobSchema], directory: '');

});


tearDownAll(() async {

  await isar.close();

});

(Тестирование Stream’ов)

import 'package:isar/isar.dart';

part 'job_data.g.dart';


@collection

class JobData {

  Id id = Isar.autoIncrement;

  late String title;

}

class HomeBloc {

  HomeBloc({required this.isar}) {

    _streamSubscription = isar.jobDatas

      .where()

      .watch(fireImmediately: true)

      .listen((event) {

        _streamController.add(event);

      });

  }


  final Isar isar;

  final _streamController = 

        StreamController<List<JobData>>.broadcast();

  StreamSubscription? _streamSubscription;

  Stream<List<JobData>> get data => _streamController.stream;


  void close() {

    _streamSubscription?.cancel();

    _streamController.close();

    _streamSubscription = null;

  }

}

void main() {

  late Isar isar;

  late HomeBloc homeBloc;


  setUp(() async {

    await isar.writeTxn(() async => isar.clear());

    homeBloc = HomeBloc(isar: isar);

  });


  tearDown(() {

    homeBloc.close();

  });


  setUpAll(() async {

    await Isar.initializeIsarCore(download: true);

    isar = await Isar.open(

      [JobDataSchema],

      directory: '',

    );

  });


  tearDownAll(() {

    isar.close();

  });

}

test('data should emit what Isar.watchData emits', () async {

  expectLater(

    homeBloc.data,

    emitsInOrder([

      [],

      [JobData()..title = 'IT'],

      [JobData()..title = 'IT', JobData()..title = 'Teacher'],

  ]));


  // put data to Isar

  await isar.writeTxn(() async {

    isar.jobDatas.put(JobData()..title = 'IT');

  });

  await isar.writeTxn(() async {

    isar.jobDatas.put(JobData()..title = 'Teacher');

  });

});

(Функция resetMocktailState)

tearDown(() {

  resetMocktailState();

});

(Заключение)

Хотите связаться с владельцем
компании напрямую?
Дмитрий Тарасов
Дмитрий Тарасов
СЕО

НАПИСАТЬ