Некоторое время назад я доработал пакет 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

Комментарии (0)