[官网文档翻译]Flutter持久化库drift - 测试

11,085 阅读2分钟

「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战」。

Flutter持久化库drift(原moor)官方文档翻译汇总 - 掘金 (juejin.cn)

本文翻译自 drift 的 官方文档 Testing (simonbinder.eu)

肉翻多有不足,不吝赐教。


重要通知: moor 已改名为 drift 。更多信息[中文]。

测试

为 drift 数据库写单元测试的指南。

使用 drift 的 Flutter 应用一直可以在真机上用 集成测试 来测试。 该指南聚集于为 drift 编写的数据库来编写单元测试。 这些测试可在电脑上运行和调试,不需要附加准备,所以也不需要一个物理设备来运行。

准备

对于该指南,我们准备测试一个存储用户名的简单数据库。和常规的 drift 数据库相比,仅在构造方法中有一处重要的改变:明确 QueryExecutor 的参数,而不是给父类传递固定执行器的无参的构造方法(如FlutterQueryExecutor 或 NativeDatabase

import 'package:drift/drift.dart';

part 'database.g.dart';

class Users extends Table {
  IntColumn get id => integer().autoIncrement()();
  TextColumn get name => text()();
}

@DriftDatabase(tables: [Users])
class MyDatabase extends _$MyDatabase {
  MyDatabase(QueryExecutor e) : super(e);

  @override
  int get schemaVersion => 1;

  /// 创建一个用户,返回他们的 id.
  Future<int> createUser(String name) {
    return into(users).insert(UsersCompanion.insert(name: name));
  }

  /// 用[newName].id]对应的[newName]改变一个相应[id]用户的用户名
  Future<void> updateName(int id, String newName) {
    return update(users).replace(User(id: id, name: newName));
  }

  Stream<User> watchUserWithId(int id) {
    return (select(users)..where((u) => u.id.equals(id))).watchSingle();
  }
}

安装 sqlite 我们不能分发一个 sqlite 安装文件作为一个 pub 包(至少不能作为在 Flutter 构建体系之外的东西),所以需要确保在你的系统中已经有了 sqlite3 的共享库。

在 macOS 上,默认已安装。

在 Linux 上,可以在 Ubuntu 上使用 libsqlite3-dev 包,在 Arch 上使用 sqlite3 包 (其它的发行版也有类似的包)。

在 Windows 上, 可以 下载 'Precompiled Binaries for Windows' 后把  sqlite3.dll 解压到环境变量 PATH 指定的目录中。然后重启设备确保应用会在变化后的 PATH 运行。

编写测试

可以用 NativeDatabase.memory() 代替 FlutterQueryExecutor 或其它实现来创建一个数据库的内存版本。一个打开数据库的合适位置是在 package:test 包的 setUp 和 tearDown 方法:

import 'package:drift/native.dart';
import 'package:test/test.dart';
// 上面定义的文件,当然可以测试任何 drift 数据库。
import 'database.dart'; 

void main() {
  MyDatabase database;

  setUp(() {
    database = MyDatabase(NativeDatabase.memory());
  });
  tearDown(() async {
    await database.close();
  });
}

在适当的位置完成准备后,最终可以如下写一些测试:

test('users can be created', () async {
  final id = await database.createUser('some user');
  final user = await database.watchUserWithId(id).first;

  expect(user.name, 'some user');
});

test('stream emits a new user when the name updates', () async {
  final id = await database.createUser('first name');

  final expectation = expectLater(
    database.watchUserWithId(id).map((user) => user.name),
    emitsInOrder(['first name', 'changed name']),
  );

  await database.updateName(id, 'changed name');
  await expectation;
});

测试迁移

drift 会帮助生成用于 schema 迁移的代码。更多详细内容参考该指南