Cucumber-js: Вызов шагов из определений шагов

Созданный на 1 июн. 2011  ·  31Комментарии  ·  Источник: cucumber/cucumber-js

Разрешить вызов шагов из определений шагов.

https://github.com/cucumber/cucumber/wiki/Calling-Steps-from-Step-Definitions

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

:-1: :-1: :-1: :-1: :-1:

Вызов шагов из stepdefs — это одна из тех функций, которые я бы никогда не добавил в Cucumber (-Ruby), потому что это дает людям столько веревок, на которых они могут повеситься. Это произошло из-за того, что пошаговые определения Ruby используют анонимные замыкания, которые вы не можете вызывать откуда-либо еще (если только вы не пройдете через обручи).

С JavaScript ситуация другая; Определения шагов используют первоклассные функции!

function x_is_something(x, cb) {
  console.log('x', x);
  cb();
}

Given(/x is (.*)/, x_is_something);

Given(/super x/, function(cb) {
  x_is_something(97, cb);
});

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

Когда это будет реализовано, имейте в виду, что мы планируем объявить устаревшим все, кроме #steps , для этого в огурце-rb. См. https://github.com/cucumber/cucumber/issues/68 .

Спасибо, Мэтт. -js будет поддерживать только шаги().

Мне это нравится!

Есть ли прогресс в этом? Кажется, это довольно важная функция.

Это не планируется как часть текущей вехи (0.3). Это _должно_ быть частью 0.4.

@mattwynne Думаю, мы тоже хотим поддержать step() . Я прав?

@jbpros, я думаю. Может быть, вы могли бы начать с #step . Его проще реализовать, потому что вы просто вызываете шаг, а не анализируете корнишон.

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

В конечном счете, если мы собираемся поддерживать это, я бы предпочел, чтобы это было реализовано в Gherkin, чтобы у вас был способ определить макрошаг, который сопоставляется с кучей других низкоуровневых шагов. Затем Cucumber просто получает указание вызывать более низкие уровни, и ему вряд ли нужно знать, что происходит какое-либо сопоставление. Это было бы моим предпочтением.

TL;DR: Должны ли мы действительно добавить steps() / step() в Cucumber.js (и -jvm, -ruby 2 и т. д.)?

Я полностью согласен с тобой, Мэтт. _К сожалению_, сейчас это самая востребованная функция на Cucumber.js.

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

Однако с точки зрения программиста определения шагов выглядят точно так же, как и методы. Сегодня я вижу в этом слабость Cucumber_s_. Определения шагов не должны быть представлены как API, а скорее как явная карта перевода, так сказать, словарь.

У @msassak уже были интересные мысли по этому поводу, и я думаю, что он проделал отличную работу, перемоделировав эти «отображения» в Cucumber 2.0.

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

:-1: :-1: :-1: :-1: :-1:

Вызов шагов из stepdefs — это одна из тех функций, которые я бы никогда не добавил в Cucumber (-Ruby), потому что это дает людям столько веревок, на которых они могут повеситься. Это произошло из-за того, что пошаговые определения Ruby используют анонимные замыкания, которые вы не можете вызывать откуда-либо еще (если только вы не пройдете через обручи).

С JavaScript ситуация другая; Определения шагов используют первоклассные функции!

function x_is_something(x, cb) {
  console.log('x', x);
  cb();
}

Given(/x is (.*)/, x_is_something);

Given(/super x/, function(cb) {
  x_is_something(97, cb);
});

CLOSED (WONTFIX) :молоток:

Я не уверен, что понимаю, чем здесь step() будет лучше, чем простой вызов функции JS. Разве это не то, что он в конечном итоге сделает, с дополнительным уровнем косвенности (т.е. определение шага для выполнения запроса GET для конкретного пользователя, который все еще необходимо преобразовать в функцию JS)?

Я заметил, что вы написали _поскольку у меня нет возможности запустить сценарий_, вы имели в виду шаг или это преднамеренный сценарий (в последнем случае я вижу, что вы пытаетесь сделать, я думаю).

Вы по-прежнему можете определять пользователей в фоновом режиме и перебирать их на шаге When .

Feature:
  Background:
    Given a valid user called Simon
    And a valid user called Sarah
    And a valid user called Johnny

  Scenario Outline:
    When each valid user sends a GET request to /search<query>
    Then everyone's request response code is 400
    And everyone's request response body starts with <body>

  Examples:
    | query  | body |
    | ?foo=1 | ...  |

И да, это означает сохранение ответов на запросы в массиве и повторение их. Это так плохо?

Что ж, если у вас есть какой-то поток (например, процесс оформления заказа) и вы хотите перейти на страницу окончательного подтверждения, вы можете пройти через шаги, определенные (где-то) в определениях шагов.
Я согласен с тем, что вы также можете где-то определить функцию и вызвать ее из определения шага. Но это сводит к минимуму усилия по перемещению его от шагов к функционированию. Если вы где-то в BDD описали какой-то поток, вам не нужно тратить дополнительное время на перенос его в отдельную библиотеку, вы можете просто вызывать определения шагов.

Вызов одного единственного шага почти бесполезен. Я думал о портировании всех функций ruby ​​step(s) здесь. Но так как мой запрос закрылся, я бы не стал тратить на него время.

Спасибо.

Так грустно, что это не исправит, как говорит @cono : вызов одного шага почти бесполезен, реальные случаи - более сложные операции.

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

Хай! Я создал библиотеку, которая делает именно то, что вы просите (вызовите шаг из другого шага), посмотрите здесь: https://github.com/hackhat/cucumberry
Обратная связь приветствуется!

@hackhat Выглядит очень круто. Обычно мне нравится синхронизирующая часть определения шага. Огурец-про только плагин для огурца.js?

@ jlin412 Я действительно не знаю, как звонить, но это как помощник для огурца. Спасибо за отзыв

@hackhat Чтобы создать шаг синхронизации, мне нужно будет использовать синтаксис: this.addStep(...)? Нужно ли будет использовать selenium-sync вместо protractor.js/webdriver.js?

@ jlin412 вы можете использовать только плагин синхронизации, посмотрите в документации, как это сделать. Я на мобильном телефоне, поэтому не могу дать вам точные шаги. Если вы можете подождать, я объясню лучше около 23:30 по Португалии.

@hackhat, пожалуйста, измените название вашего проекта на другое. См. хакхат/огурец-про#1

@aslakhellesoy Изменено имя на https://github.com/hackhat/cucumberry

@aslakhellesoy Тогда как связать пошаговые вызовы? Нравится следить?

function x_is_something(x, cb) {
  console.log('x', x);
  this.x = x;
  cb();
}
function y_is_something(y, cb) {
  console.log('y', y);
  this.y = y;
  cb();
}

Given(/super z/, function(cb) {
  x_is_something(97, cb);
  y_is_something(8, cb);
});

Это не очень хорошо работает, так как x_is_something вызовет обратный вызов до того, как y_is_something успеет завершить свою работу.

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

Given(/super z/, function(cb) {
  x_is_something.bind(this)(97, cb);
  y_is_something.bind(this)(8, cb);
});

У кого-нибудь были решения этих проблем?

Вам нужно использовать асинхронность и использовать параллельную функцию. Таким образом вы вызываете
основной cb только после завершения обоих подвызовов.
О привязке вы можете использовать это с привязкой или использовать переменную закрытия.

Чт, 14 мая 2015 г., 00:15 Юн Цзя, [email protected] написал:

@aslakhellesoy https://github.com/aslakhellesoy Тогда как связать
пошаговые звонки? Нравится следить?

функция x_is_something(x, cb) {
console.log('х', х);
это.х = х;
КБ();
} функция y_is_something (y, cb) {
console.log('у', у);
это.у = у;
КБ();
}

Учитывая (/супер z/, функция (cb) {
x_is_something(97, cb);
y_is_something(8, cb);
});

Это не очень хорошо работает, так как x_is_something вызвал бы
обратный вызов до того, как y_is_something сможет завершить свою работу.

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

Учитывая (/супер z/, функция (cb) {
x_is_something.bind(this)(97, cb);
y_is_something.bind(this)(8, cb);
});

У кого-нибудь были решения этих проблем?


Ответьте на это письмо напрямую или просмотрите его на GitHub
https://github.com/cucumber/cucumber-js/issues/11#issuecomment -101845619
.

+1, это должно быть частью библиотеки.

Что предложил @mattwynne (добавьте функцию корнишона, которая поддерживает повторное использование кода):

    When a
    Then x
    When b
    Then y

---------------------------------

    Define x
        Then p
        And y
        And q

---------------------------------

    Step a
        ...
    Step b
        ...
    Step p
        ...
    Step q
        ...
    Step y
        ...

---------------------------------

Что предложил @aslakhellesoy (извлечение дублированного кода в функции js):

    When a
    Then x
    When b
    Then y

---------------------------------

    Step a
        ...
    Step b
        ...
    Step x
        ...
        Call f(p)
        ...
    Step y
        Call f(p)

---------------------------------

    Function f(p)
        ...

---------------------------------

Вызов шагов из определений шагов

    When a
    Then x
    When b
    Then y

---------------------------------

    Step a
        ...
    Step b
        ...
    Step x
        ...
        Call y(p)
        ...
    Step y
        ...

---------------------------------

Я до сих пор не понимаю, зачем нам еще один ненужный уровень абстракции, у вас есть какое-то объяснение?

@yunjia это базовая теория обратного вызова:

Given(/super z/, function(cb) {
  x_is_something(97, function () {
    y_is_something(8, cb);
  });
});

Что касается проблемы привязки, вы должны определить эти функции как методы в вашем мире :

function World(callback) {
    this.x_is_something = function (x, callback) {
      this.x = ...
    };

    this.y_is_something = function (y, callback) {
      this.y = ...
    };

    callback(); // tell Cucumber we're finished and to use 'this' as the world instance
  };
}
module.exports.World = World;

Затем в ваших определениях шага:

Given(/super z/, function(cb) {
  var self = this;
  self.x_is_something(97, function () {
    self.y_is_something(8, cb);
  });
});

Также обратите внимание, что определения синхронных шагов поддерживаются Cucumber.js 0.5+:

Given(/super z/, function() {
  this.x_is_something(97);
  this.y_is_something(8);
});

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

Он также побуждает людей использовать Gherkin в качестве языка сценариев, чем он вовсе не является.

@inf3rno , если вы хотите повторно использовать код в stepdef, переместите тело stepdef в обычную функцию javascript и повторно используйте ее.

@jbpros

Он также побуждает людей использовать Gherkin в качестве языка сценариев, чем он вовсе не является.

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

@inf3rno inf3rno , если вы можете вызывать шаги из шагов, вы снова прыгаете в «Огурец»: имена шагов необходимо проанализировать и сопоставить с определениями шагов, которые могут быть выполнены. По сути, вы пишете сценарии корнишонов внутри корнишонов (они скрыты в определениях шагов JS, но это деталь, которая делает его еще хуже от точки зрения обслуживания).

@aslakhellesoy @jbpros Идея состоит в том, что шаги должны быть алгебраическими составными типами, а это не так.

@jbpros , я собираюсь использовать ваше решение, так как я привык программировать на Java и не беспокоиться об обещаниях :)

Кто-нибудь когда-нибудь придумывал расширение для огурца для определения шагов с точки зрения других шагов? Что-то типа

Understand I log in to {site} as {user}, {pass}
    I visit {site}
    I log in as {user}, {pass}

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

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

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