Захват вывода fmt.Println в тестах Голанга - PullRequest
0 голосов
/ 03 ноября 2019

Цель

Чтобы записать fmt.Println в тестах, чтобы я мог быть уверен, что моя программа выводит правильные данные на консоль.

Попытка1

Использование пользовательских писателей для замены os.Stdout, как это предлагается здесь . Он работает для одного теста.

Проблема для попытки 1

Когда я объявляю несколько тестов для проверки выходных данных по различным функциям, некоторые из них работают, а некоторые -не удается захватить выходные данные (выходные данные по-прежнему поступают из стандартного вывода).

Гипотеза

Как указывалось в приведенном выше блоге, это не является потокобезопасным. Некоторые из захватов будут завершены и сбрасывают стандартный вывод, в то время как другие все еще работают, предотвращая захват некоторых выходов.

Попытка решения

Чтобы установить os.Stdout вПользовательский писатель в TestMain и сбросить его в конце TestMain.

Больше проблем

Когда я пытаюсь установить os.Stdout в TestMain, программа завершается со статусом 1без сообщения об ошибке вообще. Я закомментирую код, он запускается (просто, чтобы выходные данные не были захвачены), но когда я отсоединяю их, он ломается.

Код для попытки 1 из https://medium.com/@hau12a1/golang-capturing-log-println-and-fmt-println-output-770209c791b4

func captureOutput(f func()) string {
    reader, writer, err := os.Pipe()
    if err != nil {
        panic(err)
    }
    stdout := os.Stdout
    stderr := os.Stderr
    defer func() {
        os.Stdout = stdout
        os.Stderr = stderr
        log.SetOutput(os.Stderr)
    }()
    os.Stdout = writer
    os.Stderr = writer
    log.SetOutput(writer)
    out := make(chan string)
    wg := new(sync.WaitGroup)
    wg.Add(1)
    go func() {
        var buf bytes.Buffer
        wg.Done()
        io.Copy(&buf, reader)
        out <- buf.String()
    }()
    wg.Wait()
    f()
    writer.Close()
    return <-out
}

Код для попытки 2 только для TestMain, фактическая функция захвата опущена

func TestMain(m *testing.M) {
    var err error

    reader, writer, err = os.Pipe()
    if err != nil {
        panic(err)
    }
    stdout := os.Stdout
    stderr := os.Stderr
    os.Stdout = writer // These two lines 
    os.Stderr = writer // are causing problems
    log.SetOutput(writer)

    // Create and open test database
    db, err = sql.Open("sqlite3", "test.db")
    if err != nil {
        log.Fatal(err)
    }

    Init()

    // Initialize fixtures
    fixtures, err = testfixtures.NewFolder(db, &testfixtures.SQLite{}, "testdata/fixtures")
    if err != nil {
        log.Fatal(err)
    }

    result := m.Run()

    os.Stdout = stdout
    os.Stderr = stderr
    log.SetOutput(os.Stderr)

    // Delete test database
    CloseDB()
    if err != nil {
        log.Fatal(err)
    }
    err = os.Remove("./test.db")
    if err != nil {
        log.Fatal(err)
    }
    os.Exit(result)
}

Вывод ошибки для попытки два вообще не полезен

exit status 1
FAIL    gitlab.com/haowenl/diary/cmd    0.320s

Так как мне поступить об этом?

Спасибо!

...