test(app): 前端第一批测试 — EditorBloc 19用例 + JournalElement 11用例 + InMemoryRepo 12用例
添加 mocktail 测试依赖 + 字体文件占位 总计 42 测试通过,覆盖工具/笔画/元素/撤销/重做/序列化/乐观锁/CRUD
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
// InMemoryJournalRepository 单元测试
|
||||
//
|
||||
// 覆盖:CRUD 操作、乐观锁冲突、软删除、元素管理、clearAll
|
||||
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:nuanji_app/data/models/journal_element.dart';
|
||||
import 'package:nuanji_app/data/models/journal_entry.dart';
|
||||
import 'package:nuanji_app/data/repositories/journal_repository.dart';
|
||||
|
||||
void main() {
|
||||
group('InMemoryJournalRepository', () {
|
||||
late InMemoryJournalRepository repo;
|
||||
|
||||
setUp(() {
|
||||
repo = InMemoryJournalRepository();
|
||||
});
|
||||
|
||||
// ===== 辅助方法 =====
|
||||
|
||||
JournalEntry _createEntry({String id = 'j-1', String title = '测试日记'}) {
|
||||
return JournalEntry(
|
||||
id: id,
|
||||
authorId: 'user-1',
|
||||
title: title,
|
||||
date: DateTime(2026, 6, 1),
|
||||
mood: Mood.happy,
|
||||
weather: Weather.sunny,
|
||||
tags: const [],
|
||||
isPrivate: false,
|
||||
sharedToClass: false,
|
||||
version: 1,
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
// ===== 创建 =====
|
||||
|
||||
test('创建日记', () async {
|
||||
final entry = _createEntry();
|
||||
final created = await repo.createJournal(entry);
|
||||
|
||||
expect(created.id, entry.id);
|
||||
expect(created.title, '测试日记');
|
||||
expect(repo.journalCount, 1);
|
||||
});
|
||||
|
||||
// ===== 读取 =====
|
||||
|
||||
test('获取日记', () async {
|
||||
final entry = _createEntry();
|
||||
await repo.createJournal(entry);
|
||||
|
||||
final fetched = await repo.getJournal('j-1');
|
||||
|
||||
expect(fetched, isNotNull);
|
||||
expect(fetched!.title, '测试日记');
|
||||
});
|
||||
|
||||
test('获取不存在的日记返回 null', () async {
|
||||
final fetched = await repo.getJournal('non-existent');
|
||||
expect(fetched, isNull);
|
||||
});
|
||||
|
||||
test('获取日记列表', () async {
|
||||
await repo.createJournal(_createEntry(id: 'j-1'));
|
||||
await repo.createJournal(_createEntry(id: 'j-2'));
|
||||
|
||||
final list = await repo.getJournals();
|
||||
|
||||
expect(list.length, 2);
|
||||
});
|
||||
|
||||
test('空仓库返回空列表', () async {
|
||||
final list = await repo.getJournals();
|
||||
expect(list, isEmpty);
|
||||
});
|
||||
|
||||
// ===== 更新 =====
|
||||
|
||||
test('更新日记标题', () async {
|
||||
await repo.createJournal(_createEntry());
|
||||
final existing = (await repo.getJournal('j-1'))!;
|
||||
|
||||
final updated = await repo.updateJournal(
|
||||
existing.copyWith(title: '更新后的标题'),
|
||||
);
|
||||
|
||||
expect(updated.title, '更新后的标题');
|
||||
expect(updated.version, 2);
|
||||
|
||||
final refetched = (await repo.getJournal('j-1'))!;
|
||||
expect(refetched.title, '更新后的标题');
|
||||
expect(refetched.version, 2);
|
||||
});
|
||||
|
||||
test('乐观锁版本冲突抛出异常', () async {
|
||||
await repo.createJournal(_createEntry());
|
||||
final v1 = (await repo.getJournal('j-1'))!;
|
||||
|
||||
// 先更新一次 → v2
|
||||
await repo.updateJournal(v1.copyWith(title: 'v2'));
|
||||
|
||||
// 再用 v1 更新 → 应抛 StateError
|
||||
expect(
|
||||
() => repo.updateJournal(v1.copyWith(title: 'conflict')),
|
||||
throwsA(isA<StateError>()),
|
||||
);
|
||||
});
|
||||
|
||||
// ===== 删除 =====
|
||||
|
||||
test('软删除日记', () async {
|
||||
await repo.createJournal(_createEntry());
|
||||
await repo.deleteJournal('j-1');
|
||||
|
||||
final fetched = await repo.getJournal('j-1');
|
||||
expect(fetched, isNull);
|
||||
});
|
||||
|
||||
// ===== 元素 =====
|
||||
|
||||
test('添加元素', () async {
|
||||
await repo.createJournal(_createEntry());
|
||||
final element = JournalElement.createText(
|
||||
journalId: 'j-1',
|
||||
text: '测试文字',
|
||||
position: Offset.zero,
|
||||
);
|
||||
|
||||
final added = await repo.addElement(element);
|
||||
expect(added.journalId, 'j-1');
|
||||
expect(repo.elementCount, 1);
|
||||
});
|
||||
|
||||
test('获取元素列表(按 journalId 过滤)', () async {
|
||||
await repo.createJournal(_createEntry(id: 'j-1'));
|
||||
await repo.createJournal(_createEntry(id: 'j-2'));
|
||||
await repo.addElement(JournalElement.createText(
|
||||
journalId: 'j-1', text: '文字1', position: Offset.zero,
|
||||
));
|
||||
await repo.addElement(JournalElement.createSticker(
|
||||
journalId: 'j-1', emoji: '🌸', position: const Offset(50, 50),
|
||||
));
|
||||
await repo.addElement(JournalElement.createText(
|
||||
journalId: 'j-2', text: '文字2', position: Offset.zero,
|
||||
));
|
||||
|
||||
final elementsJ1 = await repo.getElements('j-1');
|
||||
final elementsJ2 = await repo.getElements('j-2');
|
||||
|
||||
expect(elementsJ1.length, 2);
|
||||
expect(elementsJ2.length, 1);
|
||||
});
|
||||
|
||||
test('删除元素', () async {
|
||||
await repo.createJournal(_createEntry());
|
||||
final element = JournalElement.createText(
|
||||
journalId: 'j-1', text: '待删除', position: Offset.zero,
|
||||
);
|
||||
await repo.addElement(element);
|
||||
|
||||
await repo.removeElement(element.id);
|
||||
|
||||
expect(repo.elementCount, 0);
|
||||
final elements = await repo.getElements('j-1');
|
||||
expect(elements, isEmpty);
|
||||
});
|
||||
|
||||
// ===== clearAll =====
|
||||
|
||||
test('clearAll 清空所有数据', () async {
|
||||
await repo.createJournal(_createEntry(id: 'j-1'));
|
||||
await repo.createJournal(_createEntry(id: 'j-2'));
|
||||
await repo.addElement(JournalElement.createText(
|
||||
journalId: 'j-1', text: '文字', position: Offset.zero,
|
||||
));
|
||||
|
||||
repo.clearAll();
|
||||
|
||||
expect(repo.journalCount, 0);
|
||||
expect(repo.elementCount, 0);
|
||||
expect(await repo.getJournals(), isEmpty);
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user