2013-07-01 3 views
4

Я хотел бы, чтобы единичный тест, который проверяет определенный флаг командной строки, находится в перечислении.Как модулировать флаги командной строки в Go?

Вот код, который я хотел бы писать тесты против:

var formatType string 

const (
text = "text" 
json = "json" 
hash = "hash" 
) 

func init() { 
const (
    defaultFormat = "text" 
    formatUsage = "desired output format" 
) 

flag.StringVar(&formatType, "format", defaultFormat, formatUsage) 
flag.StringVar(&formatType, "f", defaultFormat, formatUsage+" (shorthand)") 

} 

func main() { 
flag.Parse() 
} 

Нужный тест будет проходить только если -format равен одному из константных значений, приведенных выше. Это значение будет доступно в формате Format. Примером правильного вызова будет: program -format text

Каков наилучший способ проверить желаемое поведение?

Примечание: Возможно, я сформулировал это плохо, но отображаемый код не является самотестированием, а кодом, с которым я хочу написать модульные тесты. Это простой пример из инструмента, который я пишу, и хотел спросить, есть ли хороший способ проверить правильные входные данные для инструмента.

+2

IMHO это _not_ единичный тест: это просто какой-то простой код, который запускается после разбора флагов командной строки. «Модульные тесты» в Go написаны вместе с тестовым пакетом, см. Http://golang.org/doc/code.html#Testing, но эти тесты не запускаются во время запуска вашего приложения. Как насчет простого 'if formatType! = Text && ..&& foramtType! = "hash" {log.Fatalf ("Вы узнаете, прочитайте man-страницу ...")} '? – Volker

+1

То, что показано, это не сам тест блока, а код, с которого я хочу выполнить модульные тесты. – KevDog

+0

Оба ответа показывают вам способ тестирования тестовых флагов. В чем проблема с этим? – nemo

ответ

0

Я не уверен, согласны ли мы с термином 'unit test'. То, что вы хотите достичь, кажется мне больше похоже на довольно нормальный тест в программе. Вы, вероятно, хотите сделать что-то вроде этого:

func main() { 
    flag.Parse() 

    if formatType != text || formatType != json || formatType != hash { 
     flag.Usage() 
     return 
    } 

    // ... 
} 

К сожалению, это не так легко можно расширить Parser флага с собственными испытателями значения , так что вы должны придерживаться этого сейчас.

См. Intermernet для решения, которое определяет тип нестандартного формата и его валидатор.

9

Пользовательские испытания и обработка флагов могут быть выполнены с помощью функции flag.Var в пакете flag.

Flag.Var "определяет флаг с указанным именем и строкой использования. Тип и значение флага представлены первым аргументом типа Value, который обычно содержит определенную пользователем реализацию Value."

flag.Value любого типа, который удовлетворяет интерфейс Value, определяемый как:

type Value interface { 
    String() string 
    Set(string) error 
} 

Существует хороший пример в example_test.go файл в flag package source

Для вашего случая использования вы могли бы использовать что-то например:

package main 

import (
    "errors" 
    "flag" 
    "fmt" 
) 

type formatType string 

func (f *formatType) String() string { 
    return fmt.Sprint(*f) 
} 

func (f *formatType) Set(value string) error { 
    if len(*f) > 0 && *f != "text" { 
     return errors.New("format flag already set") 
    } 
    if value != "text" && value != "json" && value != "hash" { 
     return errors.New("Invalid Format Type") 
    } 
    *f = formatType(value) 
    return nil 
} 

var typeFlag formatType 

func init() { 
    typeFlag = "text" 
    usage := `Format type. Must be "text", "json" or "hash". Defaults to "text".` 
    flag.Var(&typeFlag, "format", usage) 
    flag.Var(&typeFlag, "f", usage+" (shorthand)") 
} 

func main() { 
    flag.Parse() 
    fmt.Println("Format type is", typeFlag) 
} 

Это, вероятно, является чрезмерным l для такого простого примера, но может быть очень полезна при определении более сложных типов флагов (связанный пример преобразует список интервалов, разделенных запятыми, в срез пользовательского типа на основе time.Duration).

EDIT: В ответ на то, как выполнять модульные тесты против флагов, самым каноническим примером является flag_test.go in the flag package source. Раздел, связанный с проверкой переменных пользовательского флага, начинается с Line 181.

+0

Отличный пример, полностью забыл о 'flag.Var' :) – nemo

+0

Спасибо! Я бы все же согласился с вашим утверждением, что это не легко * возможно. – Intermernet

+0

Если вы имеете в виду * легко *, как при установке дополнительных ограничений на флаг, тогда да, это правда. Самый гибкий способ не всегда самый краткий :) – nemo

Смежные вопросы