Какая структура BDD позволяет упростить подход к "написанию истории"?

Я пытаюсь использовать BDD очень простым способом, чтобы свести к минимуму количество Java-кода. Я хочу создать ровно два файла, один из них - моя история:

Given user is named "John Doe" 
And user is authenticated
When user changes his password to "a1b2c3"
Then user password equals to "a1b2c3"

Далее я создаю класс Java:

public class UserManipulator {
  @Given("$user is named $name")
  public User shouldExistOrBeCreated(String name) {
    User user = //...
    return user;
  }
  @Given("$user is authenticated")
  public void shouldBeLoggedIn() {
    // ...
  }
  @When("$user changes his password to $pwd")
  public void shouldChangePassword(User user, String pwd) {
    // ...
  }
  @Then("$user password equals to $pwd")
  public void shouldHaveThisPassword(User user, String pwd) {
    assertEquals(user.getPassword(), pwd);
  }
}

И что это. Я не хочу иметь больше файлов, больше тестов модулей. Я хочу, чтобы некоторые BDD-рамки находили мой файл истории, разбирали все мои файлы Java и запускали их один за другим. Можно ли достичь?

пс. Здесь важны возможные повторное использование методов Java в других моих историях. Например, это история №2:

Given user is named "Michael Doe"   <-- reuse
When user adds $100.00 to his account
Then user account balance is $100.00

Ответ 1

Мы используем Cucumber, который является структурой Ruby, но, связав JRuby с вашим проектом, вы можете легко получить доступ к своим Java-объектам. Это означает, что вы пишете свои определения шагов в Ruby, но это также минимизирует количество Java, которое вы пишете:)

Формат истории в Cucumber точно так же, как вы описываете в своем примере, а повторное использование сюжетных линий тривиально.

Ответ 2

Робот-диаграмма может представлять интерес. Вы можете прочитать информацию в руководстве пользователя здесь: http://robotframework.googlecode.com/svn/tags/robotframework-2.5.4/doc/userguide/RobotFrameworkUserGuide.html#behavior-driven-style

Robotframework написан на питоне, и новые ключевые слова могут быть реализованы в python или jython.

Существует также тезис об использовании RF для ATDD: http://www.niksula.cs.hut.fi/~jprantan/thesis/thesis_juha_rantanen.pdf

Ответ 4

Не то, что вы ищете, но вы можете взглянуть на Spock.

Ответ 5

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

Ответ 6

Я не думаю, что он обеспечивает уровень повторного использования, который вы ищете, но также смотрите Concordion, BDD рамки, подобные Fitnesse, но гораздо проще в использовании (спецификации написаны в виде обычного текста, в виде HTML-страниц). И он интегрируется непосредственно с JUnit и, следовательно, с Maven.

См. также

Ответ 7

JCM огурца - именно то, что вы ищете. Простые шаги, которые можно использовать повторно, прозрачно работают с JUnit, хорошо интегрируются с Spring (и многими другими). Единственный дополнительный файл, который должен быть добавлен, - это класс, аннотированный с помощью @RunWith (Cucumber.class) - один класс независимо от того, сколько тестов и шагов у вас есть.

Ответ 8

jBehave или огурец могут использоваться. Оба они хороши.

Для jbehave вы можете посетить: http://jbehave.org/

Теперь я использую jBehave. Я очень мало знаю о Огурце. Я мало изучил "Огурец-JVM".

Угадайте, оба они приятные

Ответ 9

Вы можете посмотреть JGiven. Вместо текстового файла для вашего сценария вы должны написать тест JUnit следующим образом:

public class UserManipulatorTest 
       extends ScenarioTest<GivenUser, WhenPasswordChange, ThenUser> {

   @Test
   public void user_can_change_his_password() {
       given().user_is_named( "John Doe" )
          .and().user_is_authenticated(); 
       when().user_changes_his_password_to( "a1b2c3" );
       then().user_password_equals_to( "a1b2c3" );
   }
}

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

public class GivenUser extends Stage<GivenUser> {
    @ProvidedScenarioState
    User user;

    public GivenUser user_is_named(String name) {
        user = //...
        return self();
    }

    public GivenUser user_is_authenticated() {
        // ...
        return self();
    }
}

public class WhenPasswordChange extends Stage<WhenPasswordChange> {
    @ExpectedScenarioState
    User user;

    public WhenPasswordChange user_changes_his_password_to(String pwd) {
        // ...
        return self();
    } 
}

public class ThenUser extends Stage<ThenUser> {
    @ExpectedScenarioState
    User user;

    public ThenUser user_password_equals_to(String pwd) {
        assertEquals(user.getPassword(), pwd);
        return self();
    }
}

Теперь вы можете повторно использовать эти сценические классы в других сценариях. В вашем примере вы можете повторно использовать класс StageEventer, и вы бы определили новые классы этапа WhenBalanceChange и ThenBalance:

public class BalanceTest 
    extends ScenarioTest<GivenUser, WhenBalanceChange, ThenBalance> {

    @Test
    public void user_can_add_balance_to_his_account() {
        given().user_is_named("Michael Doe");
        when().user_adds_$_to_his_account("$100.00");
        then().user_account_balance_is("$100.00");
    }
}

Обратите внимание, что в JGiven символ $в имени метода является заполнителем аргумента метода и будет заменен им в сгенерированном отчете.

Отказ от ответственности: Я автор JGiven.