Как проверить вывод функции (stdout / stderr) в модульных тестах Go
у меня есть простая функция, которую я хочу проверить:
func (t *Thing) print(min_verbosity int, message string) {
if t.verbosity >= minv {
fmt.Print(message)
}
}
но как я могу проверить, что функция фактически отправляет на стандартный вывод? Test:: Output делает то, что я хочу в Perl. Я знаю, что мог бы написать весь свой собственный шаблон, чтобы сделать то же самое в Go (как описано здесь):
orig = os.Stdout
r,w,_ = os.Pipe()
thing.print("Some message")
var buf bytes.Buffer
io.Copy(&buf, r)
w.Close()
os.Stdout = orig
if(buf.String() != "Some message") {
t.Error("Failure!")
}
но это много дополнительной работы для каждого теста. Я надеюсь, что есть более стандартный способ или, возможно, библиотека абстракций для обработки этого.
3 ответов
одна вещь, чтобы также помнить, нет ничего, что мешает вам писать функции, чтобы избежать шаблона.
например у меня есть приложение командной строки, которая использует log
и я написал эту функцию:
func captureOutput(f func()) string {
var buf bytes.Buffer
log.SetOutput(&buf)
f()
log.SetOutput(os.Stderr)
return buf.String()
}
затем использовал его следующим образом:
output := captureOutput(func() {
client.RemoveCertificate("www.example.com")
})
assert.Equal("removed certificate www.example.com\n", output)
используя эту библиотеку assert:http://godoc.org/github.com/stretchr/testify/assert.
вы можете сделать одну из двух вещей. Первый-использовать примеры.
пакет также выполняет и проверяет пример кода. Пример функции может включать комментарий заключительной строки, который начинается с "Output:" и сравнивается со стандартным выходом функции при выполнении тестов. (Сравнение игнорирует начальное и конечное пространство.) Вот примеры примера:
func ExampleHello() {
fmt.Println("hello")
// Output: hello
}
второй (и более подходящий, ИМО) - это используйте поддельные функции для вашего ввода-вывода. В вашем коде вы делаете:
var myPrint = fmt.Print
func (t *Thing) print(min_verbosity int, message string) {
if t.verbosity >= minv {
myPrint(message) // N.B.
}
}
и в ваших тестах:
func init() {
myPrint = fakePrint // fakePrint records everything it's supposed to print.
}
func Test...
другой вариант-использовать fmt.Fprintf
С io.Writer
что это os.Stdout
в производственном коде, но можно сказать bytes.Buffer
в тестах.
вы можете добавить оператор return в свою функцию, чтобы вернуть строку, которая фактически распечатана.
func (t *Thing) print(min_verbosity int, message string) string {
if t.verbosity >= minv {
fmt.Print(message)
return message
}
return ""
}
теперь ваш тест может просто проверить возвращаемую строку на ожидаемую строку (а не на распечатку). Возможно, немного больше в соответствии с тестовой разработкой (TDD).
и в вашем производственном коде ничего не нужно будет менять, так как вам не нужно назначать возвращаемое значение функции, если оно вам не нужно.