31

对于正在进行的项目和改进我们的开发过程,我们考虑采用TDD作为开发理念。在研究最佳实践以及如何向我的同事/开发人员“推销”新方法时,我遇到了BDD,发现它更适合我们需要的东西,并且以某种方式成为 TDD 的下一次迭代。问题是到目前为止我只尝试了Dan North开发的工具JBehave我不能说我很惊讶。

设置在我看来很麻烦,我找不到非常合适的文档。另一方面,我也尝试过使用groovy工具,到目前为止我还挺喜欢它的。

问:有什么合适的工具可用于 BDD?
问:你会改用 spock 来处理引入另一种语言的开销吗?

4

6 回答 6

44

行为驱动开发只是一种无需任何工具即可使用的技术。您可以只编写 BDD 风格的测试 - 例如,使用此方法启动测试方法should并引入一些单独的功能。Whenthen部分可以只用评论替换,例如

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

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

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

我对上述框架的看法:

  • JBehave的问题在于测试看起来像一艘复杂的宇宙飞船。另一方面,它对您的规格有很好的输出。

  • spock真的很酷。紧凑的语法,漂亮的输出,很多功能,用强大的 groovy 语言编写,这意味着可以与geb结合使用。它很时髦,对某人来说可能非常重要。

  • scalatest(用 scala 编写)和easyb(用 groovy 编写)都具有与 spock 相同的缺点。“...应该...”和“Given...Then”表示法。规范在 .story 文件中,步骤实现在 Java 类中。这种方法非常适合作为定义规范的协作和通信工具,但通常对于低级编码来说开销太大。

我还认为最成功的 Java BDD 框架是那些不是用 Java 编写的,因为 Java 语言没有 Groovy 或 Scala 那样的 DSL(领域特定语言)创建灵活性。

于 2013-04-17T09:56:38.037 回答
16

作为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 编写测试。

于 2014-08-09T17:48:36.580 回答
14

Unless your product owner/qa/customer need to be able to read the tests, use Spock. It is very simple tool, but improves readability of tests. Thanks to it's powerful features you don't need Mockito, Hamcrest nor AssertJ. And it has superb parametrized tests. In fact, it is "just" a better JUnit - a general tool for automated execution of simple tasks, be it unit tests, integration tests or acceptance tests.

Fearing Groovy? Why? It is very similar to java. The more you learn it, the more expressive and shorter your code is. Your tests will be shorter and more readable. Groovy is gateway drug to the better side of JVM.

Don't like dynamic languages? Well, it is tests, and tests are run by CI server after every commit, right? If your code breaks, you will know it after few minutes. Don't have CI server or not running tests regularly? Then don't bother with choosing a test framework and go fix your process. Broken tests are useless and if you don't run the tests regularly, they will break soon.

Go with JBehave/Cucumber if you need it; Otherwise, use Spock.

于 2014-01-28T21:34:55.293 回答
4

另一种选择是 Spectrum - 请参阅https://github.com/greghaskins/spectrum

Spectrum 支持 RSpec/Mocha 语法,并且在其下一个版本中还将支持 Gherkin 语法,以及 JUnit 规则集成(因此它通过@Ruleand@ClassRule成员与 Mockito、Spring 等进行互操作)。

全面披露——我是这个操作系统项目的贡献者

例子:

@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);
        });
    });
}}

Spectrum 在您的 JUnit 控制台中输出分层测试结果。它的优势在于将规范执行的 Java 实现与规范定义混合在一起——这比依赖特性文件和粘合代码来解析它们的框架更直接,特别是如果需要从一个步骤传递结果的测试给另一个。

Spectrum 的目标是多语言,因此对几个现有框架的用户来说应该很熟悉。

于 2017-01-26T11:01:04.253 回答
2

试试Ginkgo4j 。它使用 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。

(完全披露。我是这个库的作者)。

于 2016-06-17T03:22:44.503 回答
1

很好的讨论!我不知道 JGiven,但我会看看它。

此外,我是COLA Tests的作者,这是一个支持完整 gherkin 语法(与 Cucumber 完全相同)的新框架,它非常容易设置,特别是与 JBehave 相比并且不需要 JUnit runner。

基本上只需使用您已经习惯的任何库!

这是一个示例 Spring Controller 测试(可以从文件中加载故事):

@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!"));
    }
}
于 2015-01-17T07:00:15.567 回答