Spock拡張機能のガイド

  • link:/category/testing/ [テスト]

  • Groovy

1. 概要

このチュートリアルでは、https://www.baeldung.com/groovy-spock [Spock]拡張機能を見ていきます。
場合によっては、仕様のライフサイクルを変更または強化する必要があります。 たとえば、条件付き実行の追加、ランダムに失敗する統合テストの再試行などを行います。 このために、Spockの拡張メカニズムを使用できます。
  • Spock には、さまざまな拡張機能*があり、仕様のライフサイクルにフックすることができます。

    最も一般的な拡張機能の使用方法を見てみましょう。

2. Mavenの依存関係

始める前に、https://search.maven.org/classic/#search%7Cga%7C1%7C%20(g%3A%22org.spockframework%22%20AND%20a%3A%22spock-coreをセットアップしましょう%22)%20OR%20(g%3A%22org.codehaus.groovy%22%20AND%20a%3A%22groovy-all%22)[Maven dependencies]:
<dependency>
    <groupId>org.spockframework</groupId>
    <artifactId>spock-core</artifactId>z
    <version>1.3-groovy-2.4</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>2.4.7</version>
    <scope>test</scope>
</dependency>

3. 注釈ベースの拡張

  • Spock’sの組み込み拡張機能のほとんどはアノテーションに基づいています。*

    特定の動作をトリガーするために、仕様クラスまたは機能に注釈を追加できます。

3.1. _ @ Ignore_

*いくつかの機能メソッドまたは仕様クラスを無視する必要がある場合があります。*同様に、できるだけ早く変更をマージする必要があるかもしれませんが、継続的な統合は依然として失敗します。 一部の仕様を無視しても、マージを成功させることができます。
*メソッドレベルで_ @ Ignore_を使用して、単一の指定メソッドをスキップできます。*
@Ignore
def "I won't be executed"() {
    expect:
    true
}
  • Spockはこのテストメソッドを実行しません。*そして、ほとんどのIDEはテストを_skipped_としてマークします。

    さらに、クラスレベルで__ @ Ignore __を使用できます。
@Ignore
class IgnoreTest extends Specification
テストスイートまたはメソッドが無視される理由を単に提供することができます。
@Ignore("probably no longer needed")

3.2. _ @ IgnoreRest_

同様に、_ @ IgnoreRest_アノテーションでマークできる1つを除くすべての仕様を無視できます。
def "I won't run"() { }

@IgnoreRest
def 'I will run'() { }

def "I won't run too"() { }

3.3. _ @ IgnoreIf_

場合によっては、1つまたは2つのテストを条件付きで無視したいことがあります。 その場合、引数として述語*を受け入れる_ @ IgnoreIf、_を使用できます。
@IgnoreIf({System.getProperty("os.name").contains("windows")})
def "I won't run on windows"() { }
Spockは、述語の読み取りと書き込みを容易にするために、プロパティとヘルパークラスのセットを提供します。
  • os _–オペレーティングシステムに関する情報(参照
    _spock.util.environment.OperatingSystem
    )。

  • jvm – JVMの情報(_spock.util.environment.Jvm_を参照)。

  • _sys _–マップ内のシステムのプロパティ。

  • env –マップ内の環境変数。

    __os __propertyの使用を通じて、前の例を書き換えることができます。 実際には、たとえば_isWindows()_のようないくつかの便利なメソッドを持つ_spock.util.environment.OperatingSystem_クラスです。
@IgnoreIf({ os.isWindows() })
def "I'm using Spock helper classes to run only on windows"() {}
*注意:__Spock ___uses __System.getProperty(…)__underhood。 主な目標は、複雑なルールと条件を定義するのではなく、明確なインターフェースを提供することです。*
また、前の例のように、クラスレベルで_ @ IgnoreIf_注釈を適用できます。

3.4. _ @ Requires_

場合によっては、述語ロジックを[email protected]_から反転する方が簡単な場合があります。その場合、_ @ Requires_を使用できます。
@Requires({ System.getProperty("os.name").contains("windows") })
def "I will run only on Windows"()
したがって、* _ @ Requires_はOSがWindows *の場合にのみこのテストを実行しますが、__ @ IgnoreIf、__は同じ述語を使用して、OSが_not_の場合にのみテストを実行します。
*一般的に* *無視されるときよりも、どの条件でテストを実行するかを言う方がはるかに良い*。

3.5. _ @ PendingFeature_

__TDDでは、最初にテストを作成します。 次に、これらのテストに合格するためのコードを記述する必要があります。 場合によっては、機能を実装する前にテストをコミットする必要があります。
これは、_ @ PendingFeature:_の適切な使用例です。
@PendingFeature
def 'test for not implemented yet feature. Maybe in the future it will pass'()
_ @ Ignore_と_ @ PendingFeature_には大きな違いが1つあります。 __ @ PedingFeatureでは、__testsが実行されますが、失敗は無視されます。
*テストが__ @ PendingFeature __endでエラーなしでマークされた場合、注釈の削除を思い出させるために、失敗として報告されます。*
このようにして、実装されていない機能の失敗を最初は無視できますが、将来、これらの仕様は永久に無視されるのではなく、通常のテストの一部になります。

3.6. _ @ Stepwise_

_ @ Stepwise_アノテーションを使用して、指定の順序で仕様のメソッドを実行できます。
def 'I will run as first'() { }

def 'I will run as second'() { }
*一般に、テストは決定論的である必要があります。 __ @ Stepwise __annotationの使用を避ける必要があるのはそのためです。
ただし、必要な場合は、* _ @ Stepwise_が_ @ Ignore _、_ @ IgnoreRest_、または* * _ @ IgnoreIf_ *の動作をオーバーライドしないことに注意する必要があります。 これらの注釈を_ @ Stepwise_と組み合わせることには注意が必要です。

3.7. @タイムアウト

*仕様の単一メソッドの実行時間を制限して、より早く失敗することができます:*
@Timeout(1)
def 'I have one second to finish'() { }
これは、1回の反復のタイムアウトであり、フィクスチャメソッドで費やされた時間をカウントしないことに注意してください。
デフォルトでは、_spock.lang.Timeout_はベース時間単位として秒を使用します。 ただし、*他の時間単位を指定できます:*
@Timeout(value = 200, unit = TimeUnit.SECONDS)
def 'I will fail after 200 millis'() { }
クラスレベルの_ @ Timeout_は、すべての機能メソッドに個別に適用するのと同じ効果があります。
@Timeout(5)
class ExampleTest extends Specification {

    @Timeout(1)
    def 'I have one second to finish'() {

    }

    def 'I will have 5 seconds timeout'() {}
}
*単一のspecメソッドで_ @ Timeout_を使用すると、常にクラスレベルがオーバーライドされます。*

3.8. @リトライ

場合によっては、非決定的な統合テストを行うことができます。 これらは、非同期処理などの理由で、または他の_HTTP_クライアントの応答に応じて、一部の実行で失敗する場合があります。 さらに、ビルドとCIを備えたリモートサーバーは失敗し、テストを実行して再度ビルドするように強制されます。
この状況を避けるために、メソッドまたはクラスレベルで__ @ Retry __annotationを使用して、失敗したテストを繰り返すことができます*:
@Retry
def 'I will retry three times'() { }
デフォルトでは、3回再試行します。
テストを再試行する条件を決定することは非常に便利です。 例外のリストを指定できます:
@Retry(exceptions = [RuntimeException])
def 'I will retry only on RuntimeException'() { }
または、特定の例外メッセージがある場合:
@Retry(condition = { failure.message.contains('error') })
def 'I will retry with a specific message'() { }
遅延を伴う再試行は非常に便利です。
@Retry(delay = 1000)
def 'I will retry after 1000 millis'() { }
最後に、ほとんどの場合と同様に、クラスレベルで再試行を指定できます。
@Retry
class RetryTest extends Specification

3.9. _ @ RestoreSystemProperties_

_ @ RestoreSystemProperties_を使用して環境変数を操作できます。
この注釈を適用すると、変数の現在の状態が保存され、後で復元されます。 _setup_または_cleanup_メソッドも含まれます。
@RestoreSystemProperties
def 'all environment variables will be saved before execution and restored after tests'() {
    given:
    System.setProperty('os.name', 'Mac OS')
}
*システムプロパティを操作しているときは、テストを同時に実行しないでください。*テストは非決定的である場合があります。

3.10。 人間に優しいタイトル

_ @ Title_アノテーションを使用して、人間に優しいテストタイトルを追加できます。
@Title("This title is easy to read for humans")
class CustomTitleTest extends Specification
同様に、_ @ Narrative_アノテーションと複数行の__Groovy S__tringを使用して、仕様の説明を追加できます。
@Narrative("""
    as a user
    i want to save favourite items
    and then get the list of them
""")
class NarrativeDescriptionTest extends Specification

3.11。 @見る

1つ以上の外部参照をリンクするには、__ @See__注釈を使用できます。
@See("https://example.org")
def 'Look at the reference'()
複数のリンクを渡すには、Groovy _ [] _オペランドを使用してリストを作成できます。
@See(["https://example.org/first", "https://example.org/first"])
def 'Look at the references'()

3.12。 @問題

機能メソッドが1つまたは複数の問題を指すことを示すことができます。
@Issue("https://jira.org/issues/LO-531")
def 'single issue'() {

}

@Issue(["https://jira.org/issues/LO-531", "http://jira.org/issues/LO-123"])
def 'multiple issues'()

3.13。 _ @ Subject_

最後に、_ @ Subject_を使用して、テスト中のクラスがどのクラスであるかを示すことができます。
@Subject
ItemService itemService // initialization here...
現時点では、情報提供のみを目的としています。

4. 拡張機能の構成

  • Spock構成ファイルでいくつかの拡張機能を構成できます。*これには、各拡張機能の動作の説明が含まれます。

    通常、たとえば_SpockConfig.groovy_などのGroovy__、__calledに構成ファイルを作成します。
    もちろん、* Spockは設定ファイルを見つける必要があります。*まず、__ spock.configuration __systemプロパティからカスタムの場所を読み取り、クラスパスでファイルを見つけようとします。 見つからない場合は、ファイルシステム内の場所に移動します。 それでも見つからない場合は、テスト実行クラスパスで__SpockConfig.groovy __を探します。
    最終的に、SpockはSpockユーザーのホームに移動します。これは、ホームディレクトリ内のディレクトリ__。spock __withだけです。 このディレクトリを変更するには、__ spock.user.home __と呼ばれるシステムプロパティを環境変数_SPOCK_USER_HOME._で設定します。
    この例では、_SpockConfig.groovy_ファイルを作成し、クラスパス(_src / test / resources / SpockConfig.Groovy_)に配置します。

4.1. スタックトレースのフィルタリング

構成ファイルを使用することにより、スタックトレースをフィルタリングする(またはフィルタリングしない)ことができます。
runner {
    filterStackTrace false
}
*デフォルト値は_true ._ *です
それがどのように機能するかを確認し、練習するために、_RuntimeException:_をスローする簡単なテストを作成しましょう。
def 'stacktrace'() {
    expect:
    throw new RuntimeException("blabla")
}
__filterStackTrace ___がfalseに設定されている場合、出力に次のように表示されます。
java.lang.RuntimeException: blabla

  at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
  at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
  at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
  at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
  at org.codehaus.groovy.reflection.CachedConstructor.invoke(CachedConstructor.java:83)
  at org.codehaus.groovy.runtime.callsite.ConstructorSite$ConstructorSiteNoUnwrapNoCoerce.callConstructor(ConstructorSite.java:105)
  at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallConstructor(CallSiteArray.java:60)
  at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:235)
  at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callConstructor(AbstractCallSite.java:247)
  // 34 more lines in the stack trace...
このプロパティを_true、_に設定すると、次のようになります。
java.lang.RuntimeException: blabla

  at extensions.StackTraceTest.stacktrace(StackTraceTest.groovy:10)
*念頭に置いておいてくださいが、完全なスタックトレースを確認すると便利な場合があります。*

4.2. Spock構成ファイルの条件付き機能

場合によっては、*スタックトレースを条件付きでフィルタリングする必要がある場合があります。*たとえば、Continuous Integrationツールで完全なスタックトレースを表示する必要がありますが、これはローカルマシンでは必要ありません。
環境変数などに基づいて、単純な条件を追加できます。
if (System.getenv("FILTER_STACKTRACE") == null) {
    filterStackTrace false
}
Spock構成ファイルはGroovyファイルであるため、Groovyコードのスニペットを含めることができます。

4.3. _ @ Issue_のプレフィックスとURL

以前は、_ @ Issue_アノテーションについて説明しました。 また、構成ファイルを使用してこれを構成することもできます。* _issueUrlPrefixで共通のURLパーツを定義します。 _*
もう1つのプロパティは_issueNamePrefix._です。その後、すべての_ @ Issue_ valueの前に_issueNamePrefix_ propertyが付きます。
レポートに次の2つのプロパティを追加する必要があります。
report {
    issueNamePrefix 'Bug '
    issueUrlPrefix 'https://jira.org/issues/'
}

4.4. 実行順序を最適化する

*他の非常に役立つツールは_optimizeRunOrder_ *です。 Spockは、どの仕様が失敗したか、機能メソッドの実行に必要な頻度と時間を記憶できます。
この知識に基づいて、_Spock_は最初に最後の実行で失敗した機能を実行します。 そもそも、失敗したスペックをより連続的に実行します。 さらに、最速のスペックが最初に実行されます。
この動作は、__ __configurationファイルで有効にできます。 オプティマイザーを有効にするには、__ optimizeRunOrder __propertyを使用します。
runner {
  optimizeRunOrder true
}
*デフォルトでは、実行順序のオプティマイザーは無効になっています。*

4.5. 仕様の包含と除外

Spockは特定の仕様を除外または含めることができます。 *仕様クラスに適用されるクラス、スーパークラス、インターフェイス、または注釈に頼ることができます。*ライブラリは、機能レベルの注釈に基づいて、単一の機能を除外または含めることができます。
_exclude_プロパティを使用して、クラス_TimeoutTest_からテストスイートを単純に除外できます。
import extensions.TimeoutTest

runner {
    exclude TimeoutTest
}
  • TimeoutTest とそのすべてのサブクラスは除外されます。* _TimeoutTest_が仕様のクラスに適用された注釈であった場合、この仕様は除外されます。

    注釈と基本クラスを個別に指定できます。
import extensions.TimeoutTest
import spock.lang.Issue
    exclude {
        baseClass TimeoutTest
        annotation Issue
}
上記の例は、__ @ Issue __annotationと_TimeoutTest_またはそのサブクラスを持つテストクラスまたはメソッドを除外します。*
仕様を含めるには、単に__include __propertyを使用します。 _exclude_と同じ方法で_include_のルールを定義できます。

4.6. レポートを作成する

*テスト結果と既知の注釈に基づいて、_Spock ._ *を含むレポートを生成できます。さらに、このレポートには_ @ Title、@ See、@ Issue、@ Narrative_の値などが含まれます。
構成ファイルでレポートの生成を有効にできます。 デフォルトでは、レポートは生成されません。
いくつかのプロパティの値を渡すだけです。
report {
    enabled true
    logFileDir '.'
    logFileName 'report.json'
    logFileSuffix new Date().format('yyyy-MM-dd')
}
上記のプロパティは次のとおりです。
  • _enabled _ –レポートを生成するかどうか

  • _logFileDir _–レポートのディレクトリ

  • logFileName – レポートの名前

  • logFileSuffix –生成されたすべてのレポートベース名のサフィックス
    ダッシュで区切られています

    _enabled_を_true、_に設定する場合、_logFileDir_および__logFileName __propertiesを設定することが必須です。 _logFileSuffix_はオプションです。
    システムプロパティでそれらすべてを設定することもできます:_enabled _、_ spock.logFileDir、_ _spock.logFileName_および_spock.logFileSuffix._

5. 結論

この記事では、最も一般的なSpock拡張機能について説明しました。
*それらのほとんどが注釈に基づいていることがわかっています*。 さらに、__ Spock __configurationファイルの作成方法、および使用可能な構成オプションについて説明しました。 つまり、新しく習得した知識は、効果的で読みやすいテストを書くのに非常に役立ちます。
すべてのサンプルの実装は、https://github.com/eugenp/tutorials/tree/master/testing-modules/groovy-spock [Githubプロジェクト]にあります。