我正在尝试以非常简单的方式使用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文件,然后逐个运行它们。有可能实现吗?
PS。这里重要的是我的其他故事中可能的重用 Java方法。例如,这是故事2:
Given user is named "Michael Doe" <-- reuse
When user adds $100.00 to his account
Then user account balance is $100.00
答案 0 :(得分:5)
您想看看:
此外,这个presentation on BDD in Java and Groovy可能会引起人们的兴趣。
答案 1 :(得分:5)
我们使用Cucumber这是一个Ruby框架,但通过将JRuby捆绑到您的项目中,您可以轻松访问Java对象。它确实意味着您在Ruby中编写步骤定义,但它也最大限度地减少了您编写的Java数量:)
Cucumber中的故事格式正如您在示例中所描述的那样,重复使用故事情节是微不足道的。
答案 2 :(得分:5)
机器人框架可能很有意义。您可以在此处阅读用户指南中的详细信息: http://robotframework.googlecode.com/svn/tags/robotframework-2.5.4/doc/userguide/RobotFrameworkUserGuide.html#behavior-driven-style
Robotframework是用python编写的,新的关键字可以用python或jython实现。
此处还有一篇关于RF用于ATDD的论文: http://www.niksula.cs.hut.fi/~jprantan/thesis/thesis_juha_rantanen.pdf
答案 3 :(得分:4)
在较新版本的JBehave中,您可以使用JUnitStories类,它允许一个Java类充当多个纯文本故事的运行器。这会做你需要的吗?
答案 4 :(得分:3)
不是你想要的,但你可能想看看Spock。
答案 5 :(得分:2)
我不认为它提供了你正在寻找的重用级别,但也看看Concordion,一个类似于Fitnesse的BDD框架,但更容易使用(规范是用纯文本写的,以HTML页面的形式)。它直接与JUnit集成,因此也with Maven。
答案 6 :(得分:2)
Cucumber JVM正是您所寻找的。可以重用的简单步骤,与JUnit透明地工作,与Spring(以及许多其他人)很好地集成。必须添加的唯一一个附加文件是使用@RunWith(Cucumber.class)注释的类 - 无论您有多少测试和步骤,都可以使用一个类。
答案 7 :(得分:2)
可以使用jBehave或Cucumber。两者都很好。
对于jbehave,您可以访问:http://jbehave.org/
我现在正在使用jBehave。我对黄瓜知之甚少。我对“Cucumber-JVM”的研究很少。
猜猜,他们俩都很好
答案 8 :(得分:1)
您可以查看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();
}
}
现在,您可以在其他方案中重用这些阶段类。在您的示例中,您可以重用GivenUser阶段类,然后定义新的阶段类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的作者。