【问题标题】:Behavior Driven Development for java - what framework to use? [closed]java的行为驱动开发——使用什么框架? [关闭]
【发布时间】:2013-04-08 19:17:00
【问题描述】:

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

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

问:是否有任何合适的工具可用于 BDD?
问:您会改用 spock 来处理引入另一种语言的开销吗?

【问题讨论】:

  • 嗨 Olimpiu,有different flavors of BDD。还包括非技术利益相关者是否有价值?如果是,使用FitNesseConcordion 等工具怎么样?
  • @user3632158 - 是的,非常感谢您也包括非技术利益相关者。您是否朝这个方向进行了实验?
  • 我们在团队中使用Concordion。非技术业务专家正在使用免费的所见即所得 html 编辑器 (microsoft.com/en-us/download/details.aspx?id=36179) 编写规范。然后开发人员对规范进行检测,以创建自动化验收测试。

标签: testing bdd spock automated-tests jbehave


【解决方案1】:

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

@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(领域特定语言)创建灵活性。

【讨论】:

  • 个人意见。我在 spock 方面有过很棒的经历。测试 Java 代码没有问题,而且 Java 程序员非常容易掌握 groovy。您可以从编写常规 Java 开始并继续工作,然后在学习 Groovy 时逐渐采用更简洁的风格(如果需要)。我对 Groovy 持怀疑态度,但 spock 使用起来非常愉快,它不仅可以回报学习一点 Groovy 的最小努力。
【解决方案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 编写测试。

【讨论】:

  • 我不同意你,我的朋友。您介绍的内容与 DSL 无关。它是某种用于 Java 的流畅 API(基于静态方法),但恕我直言,可读性和可用性都不高。
  • 那么,请解释一下与 Groovy DSL 的区别。顺便说一句,这里没有静态方法,这些都是实例方法。此外,我展示的示例比上面的示例要复杂得多。但是,它是否可用,每个人都应该自己决定。 JGiven 为您提供了一个比 Cucumber 或 JBehave 更易于使用的工具,并且仍然提供可供企业主阅读的场景报告。
  • 由于括号和点的数量,我很难将此类 API 称为 DSL。在 Java 中,您不能简单地跳过它们。这只是我个人的感受。
  • 也许我写了太多 Java 以至于连括号都看不到了 :-)。然而,由于 JGiven 是一个 Java 框架,它也可以在 Groovy 和 Scala 中使用。在 Groovy 中你至少可以去掉分号,在 Scala 中你也可以省略括号。
  • 对我来说很有用。我对 DSL 不感兴趣,但对使用 BDD 概念的更具可读性的单元测试非常感兴趣。我永远不会在 DSL 和纯 BDD 方法上出售整个业务,但我至少可以为我的单元测试缺乏清晰度做点什么。
【解决方案3】:

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

害怕 Groovy?为什么?它与java非常相似。你学得越多,你的代码就越有表现力和越短。您的测试将更短且更具可读性。 Groovy 是通向 JVM 更好方面的门户药物。

不喜欢动态语言?嗯,它是测试,并且测试是在每次提交之后由 CI 服务器运行的,对吗?如果您的代码中断,几分钟后您就会知道。没有 CI 服务器或没有定期运行测试?然后不要为选择测试框架而烦恼,然后去修复你的过程。损坏的测试是没有用的,如果您不定期运行测试,它们很快就会损坏。

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

【讨论】:

  • 害怕 Groovy?为什么? - 越来越多的多语种解决方案列表使得寻找人才变得更加困难。
【解决方案4】:

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

Spectrum 支持 RSpec/Mocha 语法,并且在其下一个版本中还将支持 Gherkin 语法以及 JUnit 规则集成(因此它可以通过 @Rule@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 的目标是多语言,因此对几个现有框架的用户来说应该很熟悉。

【讨论】:

    【解决方案5】:

    试一试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。

    (完全公开。我是这个库的作者)。

    【讨论】:

      【解决方案6】:

      很好的讨论!我不知道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!"));
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-04-17
        • 2011-08-26
        • 2012-02-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-18
        • 2015-11-26
        相关资源
        最近更新 更多