Подтвердить что ты не робот

Разработка поведения для Java - какие рамки использовать?

Для текущих проектов и улучшения нашего процесса разработки мы рассмотрели вопрос о принятии TDD в качестве философии развития. Изучая лучшие практики и как "продавать" новый подход к моим коллегам/разработчикам, я наткнулся на BDD и нашел, что это еще более уместно что нам нужно и как-то быть следующей итерацией TDD. Проблема в том, что до сих пор я пробовал только инструмент, разработанный Dan North, JBehave, и я не могу сказать, что я поражен.

Настройка кажется мне громоздкой, и я не мог найти для нее подходящую документацию. С другой стороны, я попробовал spock инструмент groovy, и до сих пор мне это нравится.

Q: существуют ли какие-либо правильные инструменты для BDD?
Q:, вы должны использовать вместо этого spock и справляться с накладными расходами на введение другого языка?

4b9b3361

Ответ 1

Управление поведением - это просто метод, который можно использовать без каких-либо инструментов. Вы можете просто написать тесты в стиле BDD - например. начать методы тестирования с помощью should и ввести этот отдельный метод. When и then разделы могут быть заменены только комментариями, например

@Test
public void should_do_something() {
    // given
    Something something = getSomething();

    // when
    something.doSomething();
    // then 
    assertSomething();

    // when
    something.doSomethingElse();
    // then 
    assertSomethingElse();
}

Мое мнение о вышеупомянутых рамках:

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

  • spock действительно круто. Компактный синтаксис, симпатичный вывод, множество функций, написанных мощным языком groovy, что означает возможность использования в сочетании с geb. НО это groovy, и это может быть очень важно для кого-то.

  • scalatest (написано с помощью scala) и easyb (написанный с помощью groovy) оба имеют тот же недостаток, что и spock. Значения "... должны..." и "Дано... Затем". Спецификации находятся в файлах .story, а реализации шагов - в классах Java. Этот подход очень хорошо работает как инструмент совместной работы и коммуникации для определения спецификаций, но обычно это слишком много накладных расходов для низкоуровневого кодирования.

Я также считаю, что наиболее успешными фреймворками BDD для Java являются те, которые не написаны на Java, поскольку язык Java не обладает такой гибкостью для создания DSL (Domain Specific Language), который имеет groovy или Scala.

Ответ 2

Как автор JGiven Мне нужно не согласиться с тем, что Java не имеет достаточной гибкости для создания DSL. В JGiven тесты BDD выглядят следующим образом:

@Test
public void users_can_login {
    given()
       .a_registered_user()
       .and().the_login_page_is_shown();

    when()
       .the_user_enters_correct_credentials()
       .and().the_login_button_is_pressed();

    then()
       .the_welcome_page_is_shown();
}

JGiven используется вместе с JUnit или TestNg, и вы пишете свои тесты в простой Java.

Ответ 3

Если ваш владелец продукта /qa/customer не сможет прочитать тесты, используйте Spock. Это очень простой инструмент, но улучшает читаемость тестов. Благодаря этим мощным функциям вам не нужны Mockito, Hamcrest и AssertJ. И он имеет превосходные параметризованные тесты. Фактически, это "просто" лучший JUnit - общий инструмент для автоматического выполнения простых задач, будь то модульные тесты, интеграционные тесты или приемочные тесты.

Опасаясь Groovy? Зачем? Он очень похож на java. Чем больше вы его узнаете, тем более выразительным и короче ваш код. Ваши тесты будут короче и читабельнее. Groovy - это лекарство шлюза на лучшую сторону JVM.

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

Пойдите с JBehave/Cucumber, если вам это нужно; В противном случае используйте Spock.

Ответ 4

Другой альтернативой может быть Spectrum - см. https://github.com/greghaskins/spectrum

Spectrum поддерживает синтаксис RSpec/Mocha, а в следующем выпуске также будет поддерживать синтаксис Gherkin вместе с интеграцией правил JUnit (поэтому он взаимодействует с Mockito, Spring и т.д. с помощью членов @Rule и @ClassRule).

Полное раскрытие информации - я вношу вклад в этот проект ОС

Пример:

@RunWith(Spectrum.class)
public class TestSomething {{
    Supplier<Something> freshTestObject = let(Something::new);

    describe("The component", () -> {
        it("is tested by specs", () -> {
            // the "let` above gives us a new instance of the object
            // in each spec
            freshTestObject.get().doSomething();

            // using your favourite assertion framework
            assertThat(something.get().getSomething()).isEqualTo(42);
        });
    });
}}

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

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

Ответ 5

Хорошая дискуссия! Я не знал JGiven, но я посмотрю на него.

Кроме того, я являюсь автором COLA Tests, новой структуры, которая поддерживает полный синтаксис gherkin (точно такой же, как Cucumber), это действительно легко настроить, особенно по сравнению с JBehave и не требует бегуна JUnit.

В основном просто используйте те файлы, которые вы уже использовали!

Вот пример Spring Testler Test (истории могут быть загружены из файла):

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { WebAppContext.class })
public class HelloWorldControllerTest extends BaseColaTest {

    private final String stories =
        "Feature: Introduce REST endpoint\n"
            + "Scenario: Should say hello\n"
            + "Given a web endpoint\n"
            + "When hit by a get request\n"
            + "Then the HTTP status will be OK\n"
            + "And the body will say hello world";

    @Resource
    private WebApplicationContext webApplicationContext;
    private MockMvc mockMvc;
    private ResultActions result;

    @Given("a web endpoint")
    public void given() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

    @When("hit by a get request")
    public void when() throws Exception {
        result = mockMvc.perform(get("/helloWorld"));
    }

    @Then("the HTTP status will be OK")
    public void thenOk() throws Exception {
        result.andExpect(status().isOk());
    }

    @Then("the body will say hello world")
    public void thenHello() throws Exception {
        result.andExpect(content().string("Hello World!"));
    }
}

Ответ 6

Дайте Ginkgo4j a go. Он использует Java 8 lamda для отражения подхода, используемого Ruby RSpec и Go Ginkgo.

Эта библиотека позволяет вам создавать выразительные, насыщенные содержанием тесты.

`` `

package com.github.paulcwarren.ginkgo4j.examples;

import static com.github.paulcwarren.ginkgo4j.Ginkgo4jDSL.*;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.runner.RunWith;

import com.github.paulcwarren.ginkgo4j.Ginkgo4jRunner;

@RunWith(Ginkgo4jRunner.class)
public class BookTests {
    private Book longBook;
    private Book shortBook;
    {
        Describe("Book", () -> {
            BeforeEach(() -> {
                longBook = new Book("Les Miserables", "Victor Hugo", 1488);
                shortBook = new Book("Fox In Socks", "Dr. Seuss", 24);
       });

       Context("Categorizing book length", () -> {
           Context("With more than 300 pages", () -> {
               It("should be a novel", () -> {
                   assertThat(longBook.categoryByLength(), is("NOVEL"));
               });
           });

           Context("With fewer than 300 pages", () -> {
               It("should be a short story", () -> {
                   assertThat(shortBook.categoryByLength(), is("NOVELLA"));
              });
           });
       });
       });
     }
}

`` `

Также поддерживает Spring.

(Полное раскрытие. Я являюсь автором этой библиотеки).