Некоторое время назад я доработал пакет source_gen_test Кевина Мура и добавил поддержку внешних golden‑файлов. Этот пакет используют, чтобы писать тесты для таких генераторов кода как json_serializable. Для этого используют аннотацию ShouldGenerate
из этого пакета:
@ShouldGenerate(
r'''
<Dart code to generate>
''',
)
@TestAnnotation()
class Foo {}
У этого было две проблемы:
Тяжело читать, если генерируется много кода.
Генерируемый код нельзя проверить на ошибки. Чтобы всё‑таки проверить, нужно копировать этот код во внешний файл и писать тесты на него. Потом эти две копии кода могут разойтись.
Я сделал аннотацию ShouldGenerateFile
, которая позволяет положить ожидаемый код сразу во внешний файл .dart
. Она проверит, что генератор выдаёт именно такой код, и вместе с этим вы можете писать тесты на этот код:
@ShouldGenerateFile(
'goldens/foo.dart',
partOfCurrent: true,
)
@TestAnnotation()
class Foo {}
Реальный пример: enum_map
Реальный пример тестирования генератора таким образом — в пакете enum_map.
Для заданного enum
этот пакет генерирует специализированный класс Map
с гарантией на этапе компиляции, что все константы этого enum
присутствуют там как ключи:
@enumMap
enum Fruit { apple, orange, banana }
final map = FruitMap(
apple: 1,
orange: 2,
banana: 3,
);
В сгенерированном классе больше 190 строк, поэтому хранить его во внешнем файле — единственный разумный способ.
Тест будет вот таким простым:
import 'package:enum_map/enum_map.dart';
import 'package:source_gen_test/annotations.dart';
part 'output.dart';
@ShouldGenerateFile('output.dart', partOfCurrent: true)
@enumMap
enum Fruit {
apple,
orange,
banana,
}
// Здесь обычные тесты, чтобы проверить, что класс FruitMap
// ведёт себя, как обычный Map.
(На самом деле enum_map использует мой временный форк source_gen_test_golden, потому что мы с Кевином долго обсуждали некоторые мелочи, и мне пришлось опубликовать свой форк как отдельный пакет. Но с тех пор он подтянул мою правку в свой оригинальный пакет, поэтому мой форк больше не поддерживается. Используйте пакет Кевина.)
Между делом я переписал пакет enum_map с использованием макросов, и это убрало саму необходимость таких тестов (пока нет инструментов, чтобы писать golden‑тесты на код, генерируемый макросами, но сгенерированный ими код добавляется в текущую библиотеку и, во‑первых, ломает компиляцию при синтаксических ошибках, а во‑вторых, на него сразу же можно писать тесты без дополнительных инструментов). Поэтому предлагаю опробовать и новый enum_map тоже (см. версию пре‑релиз).
Не пропускайте мои статьи, добавляйтесь в Телеграм‑канал: ainkin_com
Русские переводы реже и с задержкой здесь: ainkin_com_ru