Подтвердить что ты не робот

Как проверить панику?

В настоящее время я размышляю над тем, как писать тесты, которые проверяют, запанился ли данный фрагмент кода? Я знаю, что Go использует recover, чтобы поймать панику, но, в отличие от, например, кода Java, вы не можете точно указать, какой код следует пропустить в случай паники или что у вас есть. Поэтому, если у меня есть функция:

func f(t *testing.T) {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered in f", r)
        }
    }()
    OtherFunctionThatPanics()
    t.Errorf("The code did not panic")
}

Я не могу сказать, паниковал ли OtherFunctionThatPanics, и мы восстановились, или если функция не паниковала вообще. Как указать, какой код пропустить, если нет паники и какой код выполнить, если есть паника? Как я могу проверить, была ли какая-то паника, которую мы вызвали?

4b9b3361

Ответ 1

testing действительно не имеет понятия "успех", только сбой. Таким образом, ваш код выше прав. Вы можете найти этот стиль немного более понятным, но это в основном то же самое.

func TestPanic(t *testing.T) {
    defer func() {
        if r := recover(); r == nil {
            t.Errorf("The code did not panic")
        }
    }()

    // The following is the code under test
    OtherFunctionThatPanics()
}

Я обычно нахожу testing достаточно слабым. Вас могут заинтересовать более мощные двигатели для тестирования, такие как Ginkgo. Даже если вам не нужна полная система Гинкго, вы можете использовать только свою библиотеку-сопряжение, Gomega, которая может использоваться вместе с testing. Гомега включает в себя такие как:

Expect(OtherFunctionThatPanics).To(Panic())

Вы также можете завершить проверку паники в простой функции:

func TestPanic(t *testing.T) {
    assertPanic(t, OtherFunctionThatPanics)
}

func assertPanic(t *testing.T, f func()) {
    defer func() {
        if r := recover(); r == nil {
            t.Errorf("The code did not panic")
        }
    }()
    f()
}

Ответ 2

Если вы используете testify/assert, то это однострочный:

func TestOtherFunctionThatPanics(t *testing.T) {
  assert.Panics(t, OtherFunctionThatPanics, "The code did not panic")
}

Или, если ваш OtherFunctionThatPanics имеет подпись, отличную от func():

func TestOtherFunctionThatPanics(t *testing.T) {
  assert.Panics(t, func() { OtherFunctionThatPanics(arg) }, "The code did not panic")
}

Если вы не используете testify, то также проверьте testify/mock. Супер простые утверждения и макеты.

Ответ 3

Когда вам нужно проверить содержимое паники, вы можете придать возвращаемое значение:

func TestIsAheadComparedToPanicsWithDifferingStreams(t *testing.T) {
    defer func() {
        err := recover().(error)

        if err.Error() != "Cursor: cannot compare cursors from different streams" {
            t.Fatalf("Wrong panic message: %s", err.Error())
        }
    }()

    c1 := CursorFromserializedMust("/foo:0:0")
    c2 := CursorFromserializedMust("/bar:0:0")

    // must panic
    c1.IsAheadComparedTo(c2)
}

Если тестируемый код не вызывает панику или панику с ошибкой ИЛИ паники с сообщением об ошибке, которое вы ожидаете, тест завершится неудачно (это то, что вам нужно).

Ответ 4

Вы можете проверить, какая функция была проиндексирована, указав панику на вход

package main

import "fmt"

func explode() {
    // Cause a panic.
    panic("WRONG")
}

func explode1() {
    // Cause a panic.
    panic("WRONG1")
}

func main() {
    // Handle errors in defer func with recover.
    defer func() {
        if r := recover(); r != nil {
            var ok bool
            err, ok := r.(error)
            if !ok {
                err = fmt.Errorf("pkg: %v", r)
                fmt.Println(err)
            }
        }

    }()
    // These causes an error. change between these
    explode()
    //explode1()

    fmt.Println("Everything fine")

}

http://play.golang.org/p/ORWBqmPSVA