java的行为驱动开发 - 使用什么框架?

时间:2013-04-16 11:42:43

标签: testing bdd spock automated-tests jbehave

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

设置在我看来很麻烦,我找不到非常合适的文档。另一方面,我也尝试了spock groovy工具,到现在为止我有点喜欢它。

问:有没有适合BDD使用的工具?
问:你会使用spock来处理引入另一种语言的开销吗?

6 个答案:

答案 0 :(得分:37)

行为驱动开发只是一种无需任何工具即可使用的技术。你可以用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相同的缺点。 “......应该......”和“给定...然后”符号。规范在.story文件中,步骤实现在Java类中。这种方法作为定义规范的协作和通信工具非常有效,但对于低级编码通常会花费太多开销。

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

答案 1 :(得分:15)

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

答案 2 :(得分:13)

除非您的产品所有者/ qa /客户需要能够阅读测试,否则请使用Spock。它是一个非常简单的工具,但提高了测试的可读性。由于它强大的功能,你不需要Mockito,Hamcrest和AssertJ。它具有极好的参数化测试。事实上,它“只是”一个更好的JUnit - 一个自动执行简单任务的通用工具,无论是单元测试,集成测试还是验收测试。

害怕Groovy?为什么?它与java非常相似。学到的越多,代码就越有表现力,也越短。您的测试将更短,更易读。 Groovy是JVM更好的一面的门户药物。

不喜欢动态语言?好吧,它是测试,测试由CI服务器在每次提交之后运行,对吗?如果您的代码中断,您将在几分钟后知道它。没有CI服务器或没有定期运行测试?然后不要费心选择测试框架并修复您的过程。破碎的测试是没用的,如果你不经常进行测试,它们很快就会破裂。

如果需要,请使用JBehave / Cucumber;否则,请使用Spock。

答案 3 :(得分:3)

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

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

完全披露 - 我是此OS项目的撰稿人

示例:

@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控制台中输出分层测试结果。它的优势在于将spec执行的Java实现与spec定义混合在一起 - 这可能比依赖于特征文件和粘合代码来解析它们的框架更直接,特别是如果需要通过结果从测试的一个步骤到另一个步骤。

Spectrum旨在成为多语言,因此对于几个现有框架的用户来说似乎应该很熟悉。

答案 4 :(得分:1)

好的讨论!我不认识JGiven,但我会看看它。

此外,我是COLA Tests的作者,一个支持完整小黄瓜语法的新框架(与Cucumber完全相同),它的设置非常简单,特别是与JBehave并不需要JUnit runner。

基本上只使用你已经习惯的任何文库!

以下是Spring Controller 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!"));
    }
}

答案 5 :(得分:1)

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。

(完全披露。我是这个图书馆的作者)。