2013年6月13日木曜日

cucumber-jvm-groovyをGradleで試す

2013.06.13 追記:タイトルを誤って投稿していたため、先日投稿したものと同じ内容のものを再度アップします。

前提

 

手順


まず、以下のfeature (hello.feature) をsrc/test/resourceに配置する。なお、Rubyでは、featureはfeaturesフォルダに配置される。

Feature: Hello World
Scenario: Say hello
Given I have a hello app with "Howdy"
When I ask it to say hi
Then it should answer with "Howdy World"
view raw hello.feature hosted with ❤ by GitHub

さらに、以下のbuld.gradleを作成する。

apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'eclipse'
//build stuff
sourceCompatibility = 1.6
targetCompatibility = 1.6
configurations {
cucumberRuntime {
extendsFrom testRuntime
}
}
dependencies {
// Groovy library for groovy building!
groovy 'org.codehaus.groovy:groovy-all:2.0.0-beta-2'
/*
In order to work around a really flagrant bug ( http://issues.gradle.org/browse/GRADLE-732 )
You have to create a configuration that includes the jar.archivePath (the jar.archivePath is created by the java plugin)
and give it the same name as the cucumberRuntime configuration, or name it something different and have the cucumberRuntime
configuration extend from it as well.
VERY ANNOYING BUG
*/
cucumberRuntime files("${jar.archivePath}")
testCompile 'junit:junit:4.10'
testCompile 'info.cukes:cucumber-junit:1.0.9'
testCompile 'info.cukes:cucumber-groovy:1.0.9'
}
repositories {
mavenCentral()
}
task cucumber() {
dependsOn assemble
doLast {
javaexec {
main = "cucumber.cli.Main"
classpath = configurations.cucumberRuntime
args = ['-f', 'pretty', '--glue', 'src/test/groovy', 'src/test/resources']
}
}
}
view raw build.gradle hosted with ❤ by GitHub

この時点で、gradle cucumberを実行した結果は、以下の通り。
$ gradle cucumber
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:assemble UP-TO-DATE
:cucumber
Feature: Hello World

  Scenario: Say hello                        # hello.feature:3
    Given I have a hello app with "Howdy"
    When I ask it to say hi
    Then it should answer with "Howdy World"


You can implement missing steps with the snippets below:

Given(~'^I have a hello app with "([^"]*)"$') { String arg1 ->
    // Express the Regexp above with the code you wish you had
    throw new PendingException()
}

When(~'^I ask it to say hi$') { ->
    // Express the Regexp above with the code you wish you had
    throw new PendingException()
}

Then(~'^it should answer with "([^"]*)"$') { String arg1 ->
    // Express the Regexp above with the code you wish you had
    throw new PendingException()
}


BUILD SUCCESSFUL

Total time: 2.39 secs

上記出力の後半に出力されているテンプレートをもとに、以下のsetp definition (HelloSteps.groovy) を作成し、src/test/groogyに配置する。なお、Rubyでは、step definitionはfeatures/step_definitionsフォルダに配置される。

import cucumber.runtime.PendingException
this.metaClass.mixin(cucumber.runtime.groovy.Hooks)
this.metaClass.mixin(cucumber.runtime.groovy.EN)
Given(~'^I have a hello app with "([^"]*)"$') { String arg1 ->
// Express the Regexp above with the code you wish you had
throw new PendingException()
}
When(~'^I ask it to say hi$') { ->
// Express the Regexp above with the code you wish you had
throw new PendingException()
}
Then(~'^it should answer with "([^"]*)"$') { String arg1 ->
// Express the Regexp above with the code you wish you had
throw new PendingException()
}

3,4行目でCucmberから呼び出されるメソッドをmixinしている。これを忘れると、Cucumber実行時に必要なメソッドが見つからず、groovy.lang.MissingMethodExceptionが発生してしまうので注意。

再度gradle cucumberタスクを実行すると、cucumber.runtime.PendingExceptionが発生する。これは、step definitionからthrowされているPendingExpectionそのものであり、まだstep definitionが実装されていないことを表している。

ここから、通常はTDD的な手法でstep definitionとテスト対象の機能を実装していくのだが、今回そのあたりの手順は省略。最終的なstep definitionは以下の通り。

this.metaClass.mixin(cucumber.runtime.groovy.Hooks)
this.metaClass.mixin(cucumber.runtime.groovy.EN)
Given(~'^I have a hello app with "([^"]*)"$') { String arg1 ->
hello = new Hello(arg1)
}
When(~'^I ask it to say hi$') { ->
hi = hello.sayHi();
}
Then(~'^it should answer with "([^"]*)"$') { String arg1 ->
assert arg1 == hi
}

なお、step definition内では、コンテキストが共有される。例えば、上記では、Givenメソッドで定義したhelloインスタンス(5行目)をWhenメソッド内で参照(9行目)している。

テスト対象の機能を実装したHelloクラスは、以下の通り。このファイルは、src/main/groogyに配置する。

public class Hello {
String greeting;
public Hello(String greeting){
this.greeting = greeting
}
public String sayHi() {
return greeting + " World";
}
}
view raw Hello.groovy hosted with ❤ by GitHub

再度gradle cucumberタスクを実行する。
$ gradle cucumber
:compileJava UP-TO-DATE
:compileGroovy UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar UP-TO-DATE
:assemble UP-TO-DATE
:cucumber
Feature: Hello World

  Scenario: Say hello                        # hello.feature:3
    Given I have a hello app with "Howdy"    # HelloSteps.groovy:13
   Given I have a hello app with "Howdy"
   # HelloSteps.groovy:13
    When I ask it to say hi                  # HelloSteps.groovy:17
   When I ask it to say hi                  # HelloSteps.groovy:17
    Then it should answer with "Howdy World" # HelloSteps.groovy:21


BUILD SUCCESSFUL

Total time: 2.734 secs

Cucumberで定義したテストが、無事パスしたことが確認できる。

 

感想


Ruby版のCucumberと同様にcucumber-jvm-groovyが動作することが確認できた。ただ、実際に使用するとなると、featureをどう記述するかは、なかなか難しそう。このあたりは、Use Case Descriptionと同様の難しさがあるように思う。

 

関連リンク

0 件のコメント:

コメントを投稿