Этот вопрос: Как протестировать сценарии os.exit в Go (и самый высокий проголосовавший ответ в нем) описывает, как тестировать сценарии os.Exit()
внутри go. Поскольку os.Exit()
не может быть легко перехвачен, используемый метод заключается в повторном вызове двоичного файла и проверке значения выхода. Этот метод описан в слайд 23 на этой презентации Эндрю Джерранда (одного из основных членов команды Go); код очень прост и воспроизводится полностью ниже.
Соответствующие тестовые и основные файлы выглядят как (обратите внимание, что эта пара файлов является MVCE):
package foo
import (
"os"
"os/exec"
"testing"
)
func TestCrasher(t *testing.T) {
if os.Getenv("BE_CRASHER") == "1" {
Crasher() // This causes os.Exit(1) to be called
return
}
cmd := exec.Command(os.Args[0], "-test.run=TestCrasher")
cmd.Env = append(os.Environ(), "BE_CRASHER=1")
err := cmd.Run()
if e, ok := err.(*exec.ExitError); ok && !e.Success() {
fmt.Printf("Error is %v\n", e)
return
}
t.Fatalf("process ran with err %v, want exit status 1", err)
}
и
package foo
import (
"fmt"
"os"
)
// Coverage testing thinks (incorrectly) that the func below is
// never being called
func Crasher() {
fmt.Println("Going down in flames!")
os.Exit(1)
}
Однако этот метод, по-видимому, страдает некоторыми ограничениями:
-
Тестирование покрытия с помощью goveralls/coveralls.io не работает - см., например, пример здесь (тот же код, что и выше но вставляем в github для вашего удобства), который производит тест покрытия здесь, то есть он не записывает выполняемые тестовые функции. Учтите, что вам не нужны эти ссылки, чтобы ответить на вопрос - приведенный выше пример будет работать нормально - они просто там, чтобы показать, что произойдет, если вы поместите выше в github и пройдите все это через travis coveralls.io
-
Перезапуск тестового двоичного файла выглядит хрупким.
В частности, в соответствии с запросом, вот скриншот (а не ссылка) для отказа покрытия; красное затенение указывает, что в отношении coveralls.io речь не идет о Crasher()
.
Есть ли способ обойти это? В частности, первая точка.
На уровне голанга проблема такова:
-
Рамка Goveralls запускает
go test -cover ...
, которая вызывает вышеуказанный тест. -
Тест выше вызывает
exec.Command / .Run
без-cover
в аргументах ОС -
Безусловное размещение
-cover
и т.д. в списке аргументов непривлекательно, так как затем он запускает тест покрытия (как подпроцесс) в тесте без покрытия и анализирует список аргументов для наличия-cover
и т.д., представляется сложным решением. -
Даже если я помещаю
-cover
и т.д. в список аргументов, я понимаю, что у меня было бы два выхода покрытия, записанные в один и тот же файл, который не сработает - им потребуется слияние как-то. Самое близкое, что у меня есть, это эта проблема golang.
Резюме
То, что мне нужно, - это простой способ запустить тестирование покрытия (предпочтительно через travis, goveralls и coveralls.io), где можно обойти оба теста, где тестируемая процедура завершается с помощью os.Exit()
, и где отмечен охват этого теста. Мне бы очень хотелось, чтобы он использовал метод re-exec выше (если это может быть сделано для работы), если это можно сделать для работы.
В решении должно быть указано тестирование покрытия Crasher()
. Исключение Crasher()
из тестирования покрытия не является вариантом, так как в реальном мире то, что я пытаюсь сделать, это проверить более сложную функцию, где где-то глубоко внутри, при определенных условиях, она вызывает, например. log.Fatalf()
; то, что я тестирую на покрытие, заключается в том, что тесты для этих условий работают правильно.