66

Spock を使って例外を適切にテストするにはどうすればよいでしょうか (例: データ テーブル)。

例:validateUserユーザーが有効な場合に、異なるメッセージで例外をスローするか、例外をスローできないメソッドを持つ。

仕様クラス自体:

class User { String userName }

class SomeSpec extends spock.lang.Specification {

    ...tests go here...

    private validateUser(User user) {
        if (!user) throw new Exception ('no user')
        if (!user.userName) throw new Exception ('no userName')
    }
}

バリアント 1

これは機能していますが、真の意図はすべてのwhen / thenラベルと の繰り返し呼び出しによって混乱していますvalidateUser(user)

    def 'validate user - the long way - working but not nice'() {
        when:
        def user = new User(userName: 'tester')
        validateUser(user)

        then:
        noExceptionThrown()

        when:
        user = new User(userName: null)
        validateUser(user)

        then:
        def ex = thrown(Exception)
        ex.message == 'no userName'

        when:
        user = null
        validateUser(user)

        then:
        ex = thrown(Exception)
        ex.message == 'no user'
    }

バリアント 2

これは、コンパイル時に Spock によって発生する次のエラーのため、機能していません。

例外条件は「then」ブロックでのみ許可されます

    def 'validate user - data table 1 - not working'() {
        when:
        validateUser(user)

        then:
        check()

        where:
        user                         || check
        new User(userName: 'tester') || { noExceptionThrown() }
        new User(userName: null)     || { Exception ex = thrown(); ex.message == 'no userName' }
        null                         || { Exception ex = thrown(); ex.message == 'no user' }
    }

バリアント 3

これは、コンパイル時に Spock によって発生する次のエラーのため、機能していません。

例外条件は、最上位ステートメントとしてのみ許可されます

    def 'validate user - data table 2 - not working'() {
        when:
        validateUser(user)

        then:
        if (expectedException) {
            def ex = thrown(expectedException)
            ex.message == expectedMessage
        } else {
            noExceptionThrown()
        }

        where:
        user                         || expectedException | expectedMessage
        new User(userName: 'tester') || null              | null
        new User(userName: null)     || Exception         | 'no userName'
        null                         || Exception         | 'no user'
    }
4

7 に答える 7

8

これが私が思いついた解決策です。これは基本的にバリアント 3 ですが、try/catchブロックを使用して Spock の例外条件を使用しないようにしています (トップレベルでなければならないため)。

def "validate user - data table 3 - working"() {
    expect:
    try {
        validateUser(user)
        assert !expectException
    }
    catch (UserException ex)
    {
        assert expectException
        assert ex.message == expectedMessage
    }

    where:
    user                         || expectException | expectedMessage
    new User(userName: 'tester') || false           | null
    new User(userName: null)     || true            | 'no userName'
    null                         || true            | 'no user'
}

いくつかの注意事項:

  1. さまざまな例外をテストするには、複数の catch ブロックが必要です。
  2. asserttry/catch ブロック内で明示的な条件 (ステートメント) を使用する必要があります。
  3. when-then刺激と反応をブロックに分けることはできません。
于 2016-02-17T19:02:37.930 に答える
6

メッセージまたは例外クラス、または両方のマップを返すメソッドでメソッド呼び出しをラップできます...

  def 'validate user - data table 2 - not working'() {
        expect:
            expectedMessage == getExceptionMessage(&validateUser,user)
        where:
        user                         || expectedMessage
        new User(userName: 'tester') || null
        new User(userName: null)     || 'no userName'
        null                         || 'no user'
    }

    String getExceptionMessage(Closure c, Object... args){
        try{
            return c.call(args)
            //or return null here if you want to check only for exceptions
        }catch(Exception e){
            return e.message
        }
    }
于 2015-01-16T10:58:48.223 に答える