Cucumber-js: Как я могу указать файл определения шага для каждого файла функции?

Созданный на 2 февр. 2017  ·  18Комментарии  ·  Источник: cucumber/cucumber-js

Моя цель

Я пытаюсь создать масштабируемую структуру функций и определений шагов для большого приложения, и в первую очередь я пытался связать файлы step_definition с функциями, чтобы я мог использовать один и тот же шаблон шагов для разных определений шагов.

Мой код

Я показываю свой текущий пример:

Моя структура папок:

/features/sample.feature
/features/example.feature
/features/step_definitions/sample_steps.js
/features/step_definitions/example_steps.js
/features/step_definitions/common/common_steps.js

В моем sample.feature у меня есть:

  Scenario: Launching Cucumber
  Given I have some step definitions
   When I check some step definition with parameter "any"
   Then I should see all green "sample"

В моем example.feature у меня есть:

  Scenario: Launching Cucumber
  Given I have some step definitions
   When I check some step definition with parameter "any"
   Then I should see all green "example"

Шаги Given и When определены в файле /common/common_steps.js и работают нормально.

Шаг Then определяется как для sample_steps.js , так и для example_steps.js , но по-разному.

В моем sample_steps.js у меня есть:

Then('I should see all green {stringInDoubleQuotes}', (arg) => {
   if (arg !== 'sample') {
     throw 'I should see all green when the argument is "sample"';
   }
   return;
 });

И, наконец, в моем example_steps.js у меня есть:

Then('I should see all green {stringInDoubleQuotes}', (arg) => {
   if (arg !== 'example') {
     throw 'I should see all green when the argument is "example"';
   }
   return;
 });

Ошибка

Моя главная цель - сделать здесь все зеленым, но, конечно, это не работает, и я получаю эту очевидную ошибку:

Multiple step definitions match:
   I should see all green {stringInDoubleQuotes} - features\step_definitions\example_steps.js:6
   I should see all green {stringInDoubleQuotes} - features\step_definitions\sample_steps.js:6

Огурец-JVM

Я знаю, что в огурце-jvm мы можем указать атрибут glue , который связывает функции и step_definitions, и это именно то, что я ищу, но в огурце-js. Пример на Java:

@RunWith(Cucumber.class)
@Cucumber.Options( glue = { "com.app.stepdefinitions.common", "com.app.stepdefinitions.sample" } )
public class SampleFeature{
}

@RunWith(Cucumber.class)
@Cucumber.Options( glue = { "com.app.stepdefinitions.common", "com.app.stepdefinitions.example" } )
public class ExampleFeature{
}

Ну наконец то

Как я могу добиться того же, что и cucumbr-jvm, используя огурец-js?

Самый полезный комментарий

Объем ИМО определенно необходим. По мере роста вашего приложения количество функций увеличивается, и вы получите противоречивые описания в разных контекстах.

В моей компании наш продукт имеет сотни функций, а QA имеет тестовые примеры в диапазоне 100 000.
Если мы будем использовать cucumber , мы обязательно столкнемся с этой проблемой.

Да, я думаю, вам следует учитывать контекст, а не область действия.
У вас может быть большинство, если не все, определений ваших шагов в контексте по умолчанию (или без контекста), но должен быть способ указать контекст без необходимости использования пользовательского DSL.

Эти тесты должны быть написаны BA и QA, и любой нестандартный DSL неизбежно создаст путаницу и сопротивление.

Функция/сценарий уже предоставляет контексты по определению, поэтому синтаксис Gherkin имеет отступ.

Добавление тегов и пользовательских DSL — это обходной путь ограничения реализации (т. е. хак, IMO), а не решение.

Может быть, вы можете рассмотреть это, рассматривая https://github.com/cucumber/cucumber-js/issues/745 ?

Как насчет расширения Scenario из defineStep и передачи {Given, When, Then} в обратный вызов?

то есть:

import {defineSupportCode} from 'cucumber'

defineSupportCode(({ Scenario, Given, When, Then }) => {
  Given(...)
  When(...)
  Then(...)
  Scenario('<match scenario description>', ({ Given, When, Then}) => {
    Given('<take precedent of non-contexted>', ...)
    ...
  })
})

Все 18 Комментарий

Я пытаюсь создать масштабируемую структуру функций и определений шагов для большого приложения, и в первую очередь я пытался связать файлы step_definition с функциями, чтобы я мог использовать один и тот же шаблон шагов для разных определений шагов.

Очень интересно. Cucumber-js не имеет ничего встроенного, как пример Cucumber-Java, который вы привели. Идея, которая мне нравится в таких вещах, заключается в том, чтобы внедрить это логическое переключение в настройку вашего мира или инстанс. В любом случае вы получите только одно определение шага. У вас может быть несколько определений мира, между которыми вы переключаетесь при определении кода поддержки, или один экземпляр мира, который предоставляет различные методы в зависимости от контекста. В настоящее время мы не предоставляем файл текущего сценария для выполнения шагов, но вы можете использовать теги для определения своего контекста.

У нас на самом деле есть такая же потребность в этом. Мы используем nightwatch-cucumber для запуска тестов селена, и наше единственное решение на данный момент — добавить префикс к каждому шагу:

Given [comp1] I click on "Open dialog"

против

Given [comp2] I click on "Open dialog"

Это помогает нам избежать двусмысленных определений шагов, но приводит к действительно нечитаемым файлам функций.
Я пытался возиться с исходным кодом огурца.js, но не нашел хороших советов по добавлению поддержки этой функции.

Можно ли это реализовать с помощью каких-то хуков или альтернативных миров?

@leipert, какой пользовательский интерфейс вы представляете? Я считаю, что эта логика должна жить в мире или поддерживать несколько объектов мира. Затем определения шага просто имеют дело с разбором совпадений корнишонов и передачей их в соответствующую мировую функцию. Мы могли бы добавить опцию CLI для выбора того, какой объект мира использовать.

На данный момент, если вы хотите иметь несколько определений миров/шагов, вы можете добиться этого, поместив свой код в отдельные папки и требуя только одного из них для каждого запуска (используя параметр --require CLI).

Ну а "огуречная книга" специально отговаривает такой способ оформления ступенек. Шаг разделен между сценариями по дизайну, одно и то же предложение должно иметь одинаковое значение, несмотря на то, что функция его использует. Как только вы представите объем шагов, очень легко создать языковую ловушку.

Пока только теги близки к вашей цели в cucuber.js. Но только хуки могут объявлять, что они специфичны для тегов. Если вы уверены, что это правильный путь для ваших людей, вы можете изобрести DSL, возможно, просто как [название функции] в пошаговом шаблоне.

Спасибо, @pinxue . Очень полезный ответ. Однако я не могу этого понять:

Ну а "огуречная книга" специально отговаривает такой способ оформления ступенек.

Одна и та же фраза действия может иметь разное значение в разных контекстах. Но это нормально. Хорошо знать варианты, которые у меня есть. На самом деле, мы уже идем по внутреннему DSL, чтобы достичь этого,

Большое спасибо.

Спасибо за ваши ответы @pinxue и @robsonrosa.
Вот мои аргументы в пользу определений шага с ограниченной областью действия:

  1. _Глобальные переменные плохие и не масштабируются_:
    У нас всего около 15 файлов файлов функций с 10 сценариями в каждом, и уже сложно структурировать все определения шагов и файлы функций. Для больших приложений (скажем, 100 файлов функций с 10 сценариями со средним числом шагов 5) глобальное определение всех шагов кажется безумием, поскольку очень сложно отследить, какой файл функций использует какие шаги.
  2. _Разработчики не контролируют формулировку в файлах функций_:
    В нашем случае наше «руководство» пишет файлы функций, их трудно продать: мы делаем отличный BDD, но вам приходится ограничиваться неуклюжим кастомным DSL.
  3. _Если у Cucumber-jvm есть возможность, то почему нет Cucumber-js ?_
    Это может быть плохим аргументом 💃

Я вижу следующие подходы к решению проблемы для нас:

  1. Создайте собственный DSL с префиксами в определениях шагов
    Недостатки: Неприятно работать.
    Плюсы: не требует изменений в огурце.js
  2. Создайте glue для огурца.js
    Минусы: Может идти вразрез с идеей «Книги огурцов».
    Плюсы: паритет функций с cucumber.js
  3. Измените способ запуска тестов
    Минусы: эта функция будет доступна меньшему количеству людей.
    Плюсы: не требует изменений в огурце.js

При этом мы, вероятно, выберем 3., если сопровождающие огурца.js считают, что определения шагов с ограниченной областью действия выходят за рамки (каламбур) для этого проекта.

@robsonrosa Мне было бы интересно ваше решение, если оно у вас есть.

Объем ИМО определенно необходим. По мере роста вашего приложения количество функций увеличивается, и вы получите противоречивые описания в разных контекстах.

В моей компании наш продукт имеет сотни функций, а QA имеет тестовые примеры в диапазоне 100 000.
Если мы будем использовать cucumber , мы обязательно столкнемся с этой проблемой.

Да, я думаю, вам следует учитывать контекст, а не область действия.
У вас может быть большинство, если не все, определений ваших шагов в контексте по умолчанию (или без контекста), но должен быть способ указать контекст без необходимости использования пользовательского DSL.

Эти тесты должны быть написаны BA и QA, и любой нестандартный DSL неизбежно создаст путаницу и сопротивление.

Функция/сценарий уже предоставляет контексты по определению, поэтому синтаксис Gherkin имеет отступ.

Добавление тегов и пользовательских DSL — это обходной путь ограничения реализации (т. е. хак, IMO), а не решение.

Может быть, вы можете рассмотреть это, рассматривая https://github.com/cucumber/cucumber-js/issues/745 ?

Как насчет расширения Scenario из defineStep и передачи {Given, When, Then} в обратный вызов?

то есть:

import {defineSupportCode} from 'cucumber'

defineSupportCode(({ Scenario, Given, When, Then }) => {
  Given(...)
  When(...)
  Then(...)
  Scenario('<match scenario description>', ({ Given, When, Then}) => {
    Given('<take precedent of non-contexted>', ...)
    ...
  })
})

Я изучаю BDD на http://fitnesse.org/ , поэтому я могу смотреть на BDD иначе, чем в сообществе огурцов.

Пейджинг @richardlawrence

Это область, где Cucumber особенно самоуверен. Он основан на убеждении, что команды должны разработать вездесущий язык, в котором слова и фразы означают ровно одно и то же в контексте приложения и используются последовательно. Сохранение глобальных определений шага поддерживает положительное давление, чтобы избежать двусмысленности.

В редких случаях, когда приложение имеет несколько отдельных ограниченных контекстов (в терминах DDD), вы просто разделите свой набор Cucumber по тем же линиям, что и ваше приложение, чтобы отразить эту границу, и определения шагов будут глобальными в каждом ограниченном контексте.

Статья о работе с Cucumber и создании границ. Он реализует некоторые идеи на этой странице, но не предлагает никаких замечательных решений, поскольку @richardlawrence упомянул, что вы не можете настроить Cucumber, чтобы сосредоточиться на одном конкретном классе для определения шагов. http://confessionsofanagilecoach.blogspot.com/2017/05/teaching-cucumbers-about-boundaries.html

Как сказал @leipert , глобальные переменные - это плохо. Я думаю, что те из нас, кто работает в мире CucumberJVM, понимают только половину истории. Cucumber (не JVM) использует концепцию tidy World, которая представляет собой глобальное пространство памяти на время действия Scenario . После выполнения сценария он уничтожается. Это похоже на хорошее решение. Но... Я не вижу хорошей реализации этого шаблона в CucumberJVM. Так что, если Cucumber заставляет нас иметь плоское/глобальное пространство имен для определений шагов, а CucumberJVM имеет четкий шаблон проектирования для реализации шаблона World, то я немного счастливее. До этого момента шаблон CucumberJVM + World == слишком сложные решения. До сих пор все, что я видел, было сложнее, чем просто позволить мне контролировать, какие пошаговые функции идут с каким файлом функций. До сих пор альтернативы, которые я видел, не давали мне ничего более ценного для всех усилий/сложностей. Другие типы огурцов имеют лучшие мировые решения.

В конечном счете, даже с шаблоном World я все еще недоволен, потому что знаю, что при переходе от файла функций к шагам будет потеря информации. Если я приложу большие усилия: приведу свои файлы функций в хорошую организацию, создам хорошие имена файлов функций, объявлю свою функцию разумным способом, назову свои сценарии разумным способом - весь контекст будет выброшен в окно, и я буду вынужден для работы с глобальным пространством имен определения шага.

Я могу думать только о том, чтобы сохранить отношения вне проверок системы и просто добавить подстановочные знаки на пути к тестам и заставить их работать, даже если для этого потребуется изменить какую-либо среду с открытым исходным кодом. может дать ему шанс по мере роста нашего проекта.

Я понимаю вашу цель, но я бы не рекомендовал ее.
Я бы также рекомендовал иметь явные файлы .feature либо с фоновым оператором, либо с дополнительным шагом Given , который делает это явным.

В качестве альтернативы вы можете создать два разных файла конфигурации.
Один для пробы , другой для примера.
Затем вы можете указать на разные папки шагов.

@robsonrosa @leipert Я разделяю ваше мнение
Спустя почти два года после первого поста...
Достигли ли вы какого-либо прогресса в этом? Любое обходное решение?

@cristianmercado19 Извините, нет. Я больше не использую огуречный js.

Упс... Мне нравится способ написания функционального файла, полностью изолированного от реализации шага.
Я пытался достичь той же цели с _mocha_, но я не доволен.
Если у вас есть другая альтернатива, которая соответствует моей цели, я буду рад попробовать.
Благодарим вас за помощь @leipert .

Эта ветка была автоматически заблокирована, так как после ее закрытия не было никаких действий в последнее время. Пожалуйста, откройте новую проблему для связанных ошибок.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги