Go语言:编写可测试且隐藏密码回显的单路径代码方案问询
解决方案:单一执行路径下同时支持密码隐藏与无交互测试
核心思路是将终端回显控制的差异化逻辑封装到独立辅助函数中,让主业务函数保持完全单一的执行路径,无需根据输入源做分支判断。通过官方维护的golang.org/x/term包自动识别输入源是否为终端,透明适配读取逻辑:
import ( "bufio" "fmt" "io" "strings" "golang.org/x/term" ) func getPasswordAndUsername(reader io.Reader) (string, string) { var username string r := bufio.NewScanner(reader) fmt.Printf("ENTER USERNAME:\n") r.Scan() username = r.Text() fmt.Printf("ENTER PASSWORD:\n") password, err := readPassword(reader) if err != nil { // 根据实际需求处理错误,此处示例返回空值 return "", "" } return username, strings.TrimSpace(password) } func readPassword(r io.Reader) (string, error) { // 尝试获取输入源的文件描述符,判断是否为终端 fdProvider, ok := r.(interface{ Fd() uintptr }) if ok && term.IsTerminal(int(fdProvider.Fd())) { // 终端环境:关闭回显,读取后恢复终端状态 oldState, err := term.MakeRaw(int(fdProvider.Fd())) if err != nil { return "", err } defer term.Restore(int(fdProvider.Fd()), oldState) buf := make([]byte, 1024) n, err := r.Read(buf) if err != nil { return "", err } // 去除换行符(兼容Windows与Unix换行格式) return strings.TrimRight(string(buf[:n]), "\r\n"), nil } else { // 非终端环境(如测试用的字符串输入):直接按行读取 scanner := bufio.NewScanner(r) if scanner.Scan() { return scanner.Text(), nil } return "", scanner.Err() } }
方案优势
- 单一执行路径:主函数
getPasswordAndUsername完全没有分支判断,无论输入源是终端还是测试用的字符串读取器,执行流程完全一致。 - 透明适配:辅助函数
readPassword内部处理终端回显逻辑,对上层业务代码完全透明,无需修改主函数逻辑。 - 兼容性强:基于官方
term包,支持跨平台终端回显控制,测试场景下直接使用strings.NewReader模拟输入即可完成无交互测试。
测试示例
无需交互即可完成测试,输入内容直接通过字符串传递:
import ( "strings" "testing" ) func TestGetPasswordAndUsername(t *testing.T) { testInput := "testuser\ntestpassword123\n" reader := strings.NewReader(testInput) user, pass := getPasswordAndUsername(reader) if user != "testuser" || pass != "testpassword123" { t.Fatalf("预期用户名为'testuser'、密码为'testpassword123',实际得到用户名'%s'、密码'%s'", user, pass) } }
内容的提问来源于stack exchange,提问作者adrianmcmenamin
相关产品推荐
相关产品推荐

