用于标准输入测试的 Golang 模式

标签 go testing stdin go-cobra

编辑:Adrian 的建议是有道理的,所以我将我的代码移到一个函数中并从我的 cobra block 中调用该函数:

package cmd

import (
    "fmt"
    "log"
    "os"
    "io"

    "github.com/spf13/cobra"
    "github.com/spf13/viper"
    input "github.com/tcnksm/go-input"
)

var configureCmd = &cobra.Command{
    Use:   "configure",
    Short: "Configure your TFE credentials",
    Long:  `Prompts for your TFE API credentials, then writes them to
    a configuration file (defaults to ~/.tgc.yaml`,
    Run: func(cmd *cobra.Command, args []string) {
        CreateConfigFileFromPrompts(os.Stdin, os.Stdout)
    },
}

func CreateConfigFileFromPrompts(stdin io.Reader, stdout io.Writer) {
    ui := &input.UI{
        Writer: stdout,
        Reader: stdin,
    }

    tfeURL, err := ui.Ask("TFE URL:", &input.Options{
        Default:  "https://app.terraform.io",
        Required: true,
        Loop:     true,
        })
    if err != nil {
        log.Fatal(err)
    }
    viper.Set("tfe_url", tfeURL)

    tfeAPIToken, err := ui.Ask(fmt.Sprintf("TFE API Token (Create one at %s/app/settings/tokens)", tfeURL), &input.Options{
        Default:     "",
        Required:    true,
        Loop:        true,
        Mask:        true,
        MaskDefault: true,
        })

    if err != nil {
        log.Fatal(err)
    }
    viper.Set("tfe_api_token", tfeAPIToken)

    configPath := ConfigPath()
    viper.SetConfigFile(configPath)

    err = viper.WriteConfig()

    if err != nil {
        log.Fatal("Failed to write to: ", configPath, " Error was: ", err)
    }

    fmt.Println("Saved to", configPath)
}

那么我可以向此方法传递什么来测试输出是否符合预期?

package cmd

import (
  "strings"
  "testing"
)

func TestCreateConfigFileFromPrompts(t *testing.T) {
  // How do I pass the stdin and out to the method?
  // Then how do I test their contents?
  // CreateConfigFileFromPrompts()
}

最佳答案

func TestCreateConfigFileFromPrompts(t *testing.T) {

    var in bytes.Buffer
    var gotOut, wantOut bytes.Buffer

    // The reader should read to the \n each of two times.
    in.Write([]byte("example-url.com\nexampletoken\n"))

    // wantOut could just be []byte, but for symmetry's sake I've used another buffer
    wantOut.Write([]byte("TFE URL:TFE API Token (Create one at example-url.com/app/settings/tokens)"))

    // I don't know enough about Viper to manage ConfigPath()
    // but it seems youll have to do it here somehow.
    configFilePath := "test/file/location"

    CreateConfigFileFromPrompts(&in, &gotOut)

    // verify that correct prompts were sent to the writer
    if !bytes.Equal(gotOut.Bytes(), wantOut.Bytes()) {
        t.Errorf("Prompts = %s, want %s", gotOut.Bytes(), wantOut.Bytes())
    }

    // May not need/want to test viper's writing of the config file here, or at all, but if so:
    var fileGot, fileWant []byte
    fileWant = []byte("Correct Config file contents:\n URL:example-url.com\nTOKEN:exampletoken")
    fileGot, err := ioutil.ReadFile(configFilePath)
    if err != nil {
        t.Errorf("Error reading config file %s", configFilePath)
    }
    if !bytes.Equal(fileGot, fileWant) {
        t.Errorf("ConfigFile: %s not created correctly got = %s, want %s", configFilePath, fileGot, fileWant)
    }
}

正如@zdebra 在对他的回答的评论中强调的那样,go-input 包出现 panic 并给您错误:Reader must be a file。如果你已经习惯使用那个包,你可以通过禁用 ui 上的屏蔽选项来避免这个问题。请求你的第二个输入:

tfeAPIToken, err := ui.Ask(fmt.Sprintf("TFE API Token (Create one at %s/app/settings/tokens)", tfeURL), &input.Options{
        Default:     "",
        Required:    true,
        Loop:        true,
        //Mask:        true, // if this is set to True, the input must be a file for some reason
        //MaskDefault: true,
    })

关于用于标准输入测试的 Golang 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54024754/

相关文章:

ruby-on-rails - CasperJS + Authlogic (Rails) - 在测试之间维护登录 session

linux - 我想从另一个脚本运行一个脚本,使用相同版本的 perl,并将 IO 重新路由到类似终端的文本框

html - 多个数据发送表单Go文件到HTML

node.js - 如何在运行时使用 Node 配置覆盖配置值?

go - 检查纬度/经度点是否在区域内

java - Java 中的数据库后端 webapp 测试 [需要工具]

bash - 将标准输出的每一行作为标准输入传递给工具的新调用

node.js - 从nodejs中的stdin读取强制将\r\n转换为\n

json - 我如何在 Go 中解析 JSON?

makefile - 如何理解这个 Go makefile?