duandingqi9442 2019-01-03 14:57
浏览 130
已采纳

用于stdin测试的Golang模式

EDIT: Adrian's suggestion makes sense, so I moved my code into a function and called the function from my 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)
}

So what can I pass to this method to test that the output is as expected?

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()
}
  • 写回答

2条回答 默认 最新

  • dongtaochan0777 2019-01-11 18:14
    关注
    func TestCreateConfigFileFromPrompts(t *testing.T) {
    
        var in bytes.Buffer
        var gotOut, wantOut bytes.Buffer
    
        // The reader should read to the 
     each of two times.
        in.Write([]byte("example-url.com
    exampletoken
    "))
    
        // 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:
     URL:example-url.com
    TOKEN: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)
        }
    }
    

    As highlighted by @zdebra in comments to his answer, the go-input package is panicing and giving you the error: Reader must be a file. If you are married to using that package, you can avoid the problem by disabling the masking option on the ui.Ask for your second input:

    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,
        })
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 乌班图ip地址配置及远程SSH
  • ¥15 怎么让点阵屏显示静态爱心,用keiluVision5写出让点阵屏显示静态爱心的代码,越快越好
  • ¥15 PSPICE制作一个加法器
  • ¥15 javaweb项目无法正常跳转
  • ¥15 VMBox虚拟机无法访问
  • ¥15 skd显示找不到头文件
  • ¥15 机器视觉中图片中长度与真实长度的关系
  • ¥15 fastreport table 怎么只让每页的最下面和最顶部有横线
  • ¥15 java 的protected权限 ,问题在注释里
  • ¥15 这个是哪里有问题啊?