Постановка задачи

У себя на проекте мы использем SpecFlow для написания тестов и часто возникала необходимость генерировать уникальные данные для каждого теста. Ну, например, имя товара. Если имя не будет уникальным, то вероятно ваше приложение не даст возможность добавить новую сущность, а ели и даст, то как потом понять, что сейчас работаем с новой, а не той, с прошлого запуска.

В общем захотелось писать в сценариях какое-то ключевое слово и чтоб потом оно заменялось на лету другим значением. Я называю это – макросы.
В таком случае, сценарий вида:

должен замениться на:

Самый простой и быстрый вариант – использовать Transformation. Мы даже жили некоторое время с таким решением, но оно не позволяет конвертировать в string и в object, входящим параметром должен быть любой другой тип. Некоторое время мы жили с MacroString типом, который являлся, просто, оберткой над string. Такой вариант не самый удобный и часто вызывал вопросы “Зачем иметь такой класс?”. Так что решил я написать плагин, готорый бы препроцесил сценарии и заменял макросы на результат выполнения функции.

Регистрация плагина

Есть несколько правил, которым нужно следовать, чтобы SpecFlow подхватывал ваш плагин:

  • Имя сборки должно заканчиваться на .SpecFlowPlugin
  • Должен быть добавлен атрибут [assembly:RuntimePlugin(typeof(Plugin))]
  • Должен быть класс, который реализует интерфейс IRuntimePlugin
  • В App.config’e тестового проекта в секции plugins нужно добавить наш плагин <add name=”Macro” type=”Runtime” />

CustomizeGlobalDependencies – событие, которое возникает единажды, при загрузке сборки. В этом же событии мы регистрируем ITestExecutionEngine, который будет обрабатывать текст сценария и тут же мы подгружаем все сборки с макросами.

CustomizeTestThreadDependencies – событие, которое возникает для каждого потока теста. В этом потоке мы будем хранить все макросы чтобы генерировать их каждый раз и не терять значения.

Замена

С заменой все достаточно просто: нужно просто создать класс с методом, который будет заменять все слова, которые подпадают под регулярное выражение, на значение функции. Кроме того, значение должно храниться в классе и использоваться при следующем вызове, чтоб все замены одного выражения были эквивалентны.

Подгрузка классов

Штука в том, что SpecFlow – это плагин для VisualStudio, для которого я пишу плагин Macro.SpecFlow, для которого можно писть плагины… Так вот последние могут включены к любую сборку, эту сборку нужно указать в конфигурации и Macro.SpecFlow подгрузит все макросы.

Nuget и публикация плагина

Последний шаг – это публикация плагина. Для этого нужно создать nuget пакет и загрузить его на nuget.org

Для начала нужно создать nuspec файл и заполнить все соответствующия поля. У плагина есть зависимость на SpecFlow.CustomPlugin, поэтому нужно добавить dependency секцию и указать id пакета.

Код можно посмотреть на моем профиле в GitHub

Нашел ошибку в тексте? Выдели слово, нажми Ctrl+Enter чтобы помочь автору.