進行中のプロジェクトと開発プロセスの改善のために、開発哲学として [〜#〜] tdd [〜#〜] を採用することを検討しました。ベストプラクティスと同僚/開発者に新しいアプローチを「販売」する方法を調査しているときに、私は [〜#〜] bdd [〜#〜] に出会い、それがさらに適切であることがわかりましたTDDの次の反復である必要があります。問題は、これまで Dan North 、 JBehave によって開発された tool だけを試してみたことで、驚いたとは言えません。
セットアップは面倒なように思え、適切なドキュメントが見つかりませんでした。一方、 spock グルーヴィーなツールも試しましたが、今まではそれが好きでした。
Q:BDDに使用する適切なツールはありますか?
Q:代わりにspockを使用して、別の言語を導入するオーバーヘッドを処理しますか?
行動駆動型開発は、ツールなしで使用できる単なる手法です。 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 と組み合わせて使用できる可能性を意味します。 [〜#〜] but [〜#〜]グルーヴィーであり、誰かにとって非常に重要です。
scalatest (scalaで記述)および easyb (groovyで記述)の両方にspockと同じ欠点があります。 「... should ...」および「Given ... Then」表記。仕様は.storyファイルにあり、ステップの実装はJavaクラスにあります。このアプローチは、仕様を定義するためのコラボレーションおよびコミュニケーションツールとして非常にうまく機能しますが、通常は低すぎてオーバーヘッドが大きすぎますレベルのコーディング。
Javaの最も成功したBDDフレームワークは、Javaで記述されていないものだと思います。なぜなら、Java言語にはDSL(Domain GroovyまたはScalaが持つ特定の言語)の作成。
JGiven の著者として、JavaはDSL作成に十分な柔軟性がないというsodyに反対しなければなりません。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で記述します。
製品所有者/ qa /顧客がテストを読む必要がない限り、 Spock を使用します。これは非常にシンプルなツールですが、テストの読みやすさを向上させます。 Mockito、Hamcrest、AssertJを必要としない強力な機能のおかげです。そして、優れたパラメータ化されたテストがあります。実際、それは「単なる」より優れたJUnitです。単体テスト、統合テスト、受け入れテストなど、単純なタスクを自動実行するための一般的なツールです。
Groovyを恐れていますか?どうして? Javaに非常に似ています。学習すればするほど、コードは表現力豊かになり、短くなります。テストは短くなり、読みやすくなります。 Groovyは、JVMの優れた側面へのゲートウェイドラッグです。
動的言語が嫌いですか?まあ、それはtestsであり、テストはevery commitの後にCIサーバーによって実行されますか?コードが壊れた場合、数分後にそれを知ることができます。 CIサーバーがないか、テストを定期的に実行していませんか?その後、テストフレームワークの選択に煩わされず、プロセスを修正します。壊れたテストは役に立たないので、定期的にテストを実行しないと、すぐに壊れてしまいます。
必要な場合はJBehave/Cucumberを使用してください。それ以外の場合は、Spockを使用します。
別の代替手段はSpectrumです- https://github.com/greghaskins/spectrum を参照してください
SpectrumはRSpec/Mocha構文をサポートし、次のリリースではJUnitルール統合とともにGherkin構文もサポートします(したがって、@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コンソールに階層的なテスト結果を出力します。強みは、Java仕様の実行の実装を仕様定義と混合することです。これは、特に以下の場合に、機能ファイルとグルーコードに依存するフレームワークよりも直接的です。テストのあるステップから別のステップに結果を渡す必要があります。
Spectrumは多言語を目指しているため、いくつかの既存のフレームワークのユーザーには馴染みがあるように思われます。
良い議論です!私はJGivenを知りませんでしたが、私はそれを見ていきます。
さらに、私は COLA Tests の作成者であり、完全なガーキン構文(正確にはCucumberと同じ)をサポートする新しいフレームワークであり、JBehaveと比較して特に必要としない場合、セットアップが非常に簡単ですJUnitランナー。
基本的には、既に使用しているライブラリを使用するだけです!
次に、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!"));
}
}
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もサポートします。
(完全開示。私はこのライブラリの著者です)。