Как мне протестировать этот пакет promptui, написанный на golang? - PullRequest
0 голосов
/ 14 ноября 2018

Я новичок в golang, и я использую интерактивное приглашение с именем promptui (https://github.com/manifoldco/promptui) в моем проекте. Я уже написал несколько модульных тестов для этого проекта, но я борюсь с тем, как бы я тестировал модули этот конкретный пакет, который требует ввода.

Например, как бы я протестировал следующие строки кода (инкапсулированные в функции):

func setEmail() string {
  prompt := promptui.Prompt{Label: "Input your Email",
     Validate: emailValidations,
  }

  email, err := prompt.Run()
  if err != nil {
    color.red("failed getting email")
    os.exit(3)
  }
  return email
}

Я думаю, что мне нужно каким-то образом издеваться над stdin, но я не могу найти лучший способ сделать это в тесте.

Ответы [ 2 ]

0 голосов
/ 14 ноября 2018

Вы не должны пытаться проверять promptui, как ожидается, что его будет проверять его автор.

Что вы можете проверить:

  1. Вы отправляете правильные параметры при созданииpromptui.Prompt
  2. Вы используете promptui.Prompt в своем коде
  3. Вы правильно обрабатываете promptui.Prompt результаты

Как видите, все эти тесты неубедитесь, что promptui.Prompt работает правильно внутри.

Тесты № 2 и № 3 могут быть объединены.Вам нужно запустить свой код для макета, и если вы получили правильный результат, вы можете верить, что оба # 2 и # 3 верны.

Создать макет:

type Runner interface {
    Run() (int, string, error)
}

type promptMock struct {
    // t is not required for this test, but it is would be helpful to assert input parameters if we have it in Run()
    t *testing.T
}

func (p promptMock) Run() (int, string, error) {
    // return expected result
    return 1, "", nil
}

Вам понадобится отдельныймакет для тестирования потока ошибок.

Обновите ваш код, чтобы ввести макет:

func setEmail(runner Runner) string {
    email, err := runner.Run()
    if err != nil {
      color.red("failed getting email")
      os.exit(3)
    }
    return email
}

Теперь это тестируемый.

Создать функцию, которая создает prompt:

func getRunner() promptui.Prompt {
  return promptui.Prompt{Label: "Input your Email",
     Validate: emailValidations,
  }
} 

Напишите простой тест утверждения, чтобы убедиться, что мы создаем правильную структуру.

Единственная непроверенная строка будет setEmail(getRunner()), но она тривиальна и может охватываться другими типами тестов.

0 голосов
/ 14 ноября 2018

По какой-то причине они не экспортируют свой stdin интерфейс (https://github.com/manifoldco/promptui/blob/master/prompt.go#L49),, поэтому вы не можете его смоделировать, но вы можете напрямую смоделировать os.Stdin и предварительно заполнить его всем необходимым для тестирования Хотя я согласен с @Adrian, у него есть свои собственные тесты, поэтому в этом нет необходимости.

Извлечено и переработано / упрощено из источника: Заполните os.Stdin для функции, которая читает из него

Рефакторинг таким образом, его можно использовать для любой функции, которая читает из os.Stdin и ожидает определенную строку.

Ссылка на игровую площадку: https://play.golang.org/p/rjgcGIaftBK

func TestSetEmail(t *testing.T) {
    if err := TestExpectedStdinFunc("email@test.com", setEmail); err != nil {
        t.Error(err)
        return
    }
    fmt.Println("success")
}

func TestExpectedStdinFunc(expected string, f func() string) error {
    content := []byte(expected)
    tmpfile, err := ioutil.TempFile("", "example")
    if err != nil {
        return err
    }

    defer os.Remove(tmpfile.Name()) // clean up

    if _, err := tmpfile.Write(content); err != nil {
        return err
    }

    if _, err := tmpfile.Seek(0, 0); err != nil {
        return err
    }

    oldStdin := os.Stdin
    defer func() { os.Stdin = oldStdin }() // Restore original Stdin

    os.Stdin = tmpfile
    actual := f()
    if actual != expected {
        return errors.New(fmt.Sprintf("test failed, exptected: %s actual: %s", expected, actual))
    }

    if err := tmpfile.Close(); err != nil {
        return err
    }
    return nil
}
...