Go test 傳遞命令列引數及決議所遇到的錯誤及解決
概述
這周的服務計算作業是使用 Golang 開發 selpg 命令列程式,selpg 程式詳見 開發 Linux 命令列實用程式,筆者對其的 Golang 實作詳見 gitee ;
在好不容易實作了 selpg 所需要的函式后,當然是要對其進行測驗,但是在撰寫測驗函式程序中,遇到了許多問題,經過一番摸索嘗試后,才將其解決,在此將方法記錄下來,和大家分享;
以下將結合 selpg 中函式 ProcessArgs 來說明;selpg 中函式 ProcessArgs 負責檢查命令列引數合法性并決議,大概流程是先通過 os.Args 來檢查必選引數 -s 和 -e 是否存在,再用 pflag.XxxVarP 系結引數到相應變數,使用 pflag.Parse 決議;
Go test 傳遞命令列引數
一般情況下,我們是直接在終端輸入諸如 selpg -s1 -e1 input.txt 命令來呼叫 selpg ,但現在我們要在 go test 中傳遞 selpg -s1 -e1 input.txt ,在經過查閱 相關博客 ,發現可以使用 go test 的 -args 標簽,該標簽會把其后的所有字串當做引數傳入,所以我嘗試使用如下命令進行測驗;
go test -v -args selpg -s1 -e1 input.txt
func TestProcessArgs(t *testing.T){
var args selpgArgs
expectedArgs := selpgArgs{1, 1, "input.txt", 10, false, ""}
ProcessArgs(&args)
if args != expectedArgs {
t.Errorf("got %v, expected %v", args, expectedArgs)
}
}
結果毫無疑問地出錯了,因為使用 go test -v -args selpg -s1 -e1 input.txt 命令,得到的 os.Args 會是這樣的(“…”代表前面的路徑資訊);
.../selpg.test -test.timeout=10m0s -test.v=true selpg -s1 -e1 input.txt
我們想要的引數位于 os.Args 最后,而函式 ProcessArgs 是從 os.Args 前面開始檢查必選引數 -s 和 -e 是否存在,難道要修改源代碼中的函式 ProcessArgs 來適應測驗?好像并不是很合適;
那么如何才能拿到我們想要的引數呢?很簡單,既然需要的引數被放在了最后,那就把前面不需要的引數都去掉不就好了;
os.Args 本質上是一個 []string 陣列,,os 包被匯入時對其進行創建并賦予命令列引數值,那么我們可以對其進行切片操作,將前面不需要的都去掉即可;所以做出如下修改
func TestProcessArgs(t *testing.T){
var args selpgArgs
expectedArgs := selpgArgs{1, 1, "input.txt", 10, false, ""}
os.Args = os.Args[3:len(os.Args)]
ProcessArgs(&args)
if args != expectedArgs {
t.Errorf("got %v, expected %v", args, expectedArgs)
}
}
這樣,測驗就能順利運行,函式 ProcessArgs 能拿到需要的命令列引數并決議,但是這樣做的不足之處在于, go test 命令格式不能改變,多一個引數或者少一個引數,都可能使切片出錯,導致傳遞的引數不符合要求;
再仔細想一想,函式 ProcessArgs 從 os.Args 里拿引數,測驗中 os.Args 格式不符合要求,對 os.Args 切片又不夠靈活;既然 os.Args 本質上是一個 []string 陣列,那直接寫一個新的 []string 陣列,賦給 os.Args 不就好了;所以做出如下修改
func TestProcessArgs(t *testing.T){
var args selpgArgs
cmd := []string{"selpg", "-s1", "-e1", "input.txt"}
expectedArgs := selpgArgs{1, 1, "input.txt", 10, false, ""}
os.Args = cmd
ProcessArgs(&args)
if args != expectedArgs {
t.Errorf("got %v, expected %v", args, expectedArgs)
}
}
這樣,只使用 go test ,測驗也能夠順利運行,不需要在使用 -args 標簽傳遞引數
Go test 引數決議
以上只實作了一個測例的測驗函式,如果想增加多個測例,只需要簡單的修改即可
func TestProcessArgs(t *testing.T) {
cases := []struct {
cmd []string
expectedArgs selpgArgs
}{
{
[]string{"selpg", "-s1", "-e1"},
selpgArgs{1, 1, "", 10, false, ""},
},
{
[]string{"selpg", "-s1", "-e1", "input.txt"},
selpgArgs{1, 1, "input.txt", 10, false, ""},
},
}
for i, c := range cases {
var args selpgArgs
os.Args = c.cmd
ProcessArgs(&args)
if args != c.expectedArgs {
t.Errorf("case %v: got %v, expected %v", i, args, c.expectedArgs)
}
}
}
但是,如果 go test 測驗的話,會出現 flag redefined 引數決議錯誤
.../selpg.test flag redefined: ...
這個問題的解決思路來自 Golang : flag 包簡介 ,總的來說,flag 包被匯入時創建了 FlagSet 型別的全域物件 CommandLine ,在程式中定義的所有命令列引數變數都會被加入到 CommandLine 的 formal 屬性中
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
所以在每個測例中,除了要更新 os.Args ,還需要更新 flag.CommandLine ,所以做出如下修改
func TestProcessArgs(t *testing.T) {
cases := []struct {
cmd []string
expectedArgs selpgArgs
}{
{
[]string{"selpg", "-s1", "-e1"},
selpgArgs{1, 1, "", 10, false, ""},
},
{
[]string{"selpg", "-s1", "-e1", "input.txt"},
selpgArgs{1, 1, "input.txt", 10, false, ""},
},
}
for i, c := range cases {
var args selpgArgs
os.Args = c.cmd
pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
ProcessArgs(&args)
if args != c.expectedArgs {
t.Errorf("case %v: got %v, expected %v", i, args, c.expectedArgs)
}
}
}
總結
- 在 Go test 傳遞命令列引數,可以將引數在測驗函式中寫成
[]string陣列,再賦給os.Args即可; - 如果還使用了
flag包決議引數時,還需要用flag.CommandLine = NewFlagSet(os.Args[0], ExitOnError)更新flag.CommandLine
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/171507.html
標籤:其他
上一篇:區塊鏈共識機制技術一——POW(作業量證明)共識機制
下一篇:2020-10-12
