1

I have a small Go app with a cli using flags and I've been asked to make it more testable.

My app gets called on the command line like deploy.exe <task> <command> -tenant tenant_name -validate -package "c:\some dir\\"

Based on which task and command a different execution path is called and ultimately a func residing in another package is called like:

if command == "db" {
     dbhelper.RunDBCmds(*tenant, *validate, *package)
}

I need to write unit tests for just the flag parsing, without calling the actual functions at the end.

I'm fairly new to Go and I'm struggling figuring out how to accomplish this. I've thought about adding my Os.Args() and Flag parsing to a function that takes input and outputs a pointer of sorts to the RunDBCmds(*tenant, ...) func. However, I'm just not sure I can accomplish returning a pointer to a function.

I'd appreciate any advice on how I can make my code more testable without actually invoking the functions.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
buildmaestro
  • 1,386
  • 5
  • 22
  • 37

1 Answers1

2

If all of your tasks/commands have different sets of flags I would end up with introducing some kind of Command abstraction. The best example can be found in the Go source code itself:

base.Commands = []*base.Command{
        work.CmdBuild,
        clean.CmdClean,
        doc.CmdDoc,
        envcmd.CmdEnv,
        bug.CmdBug,
        fix.CmdFix,
        //...
}

Each command can have its own flag.FlagSet to parse command-specific flags:

// A Command is an implementation of a go command
// like go build or go fix.
type Command struct {
    // Run runs the command.
    // The args are the arguments after the command name.
    Run func(cmd *Command, args []string)

    // UsageLine is the one-line usage message.
    // The first word in the line is taken to be the command name.
    UsageLine string

    // Short is the short description shown in the 'go help' output.
    Short string

    // Long is the long message shown in the 'go help <this-command>' output.
    Long string

    // Flag is a set of flags specific to this command.
    Flag flag.FlagSet

    // CustomFlags indicates that the command will do its own
    // flag parsing.
    CustomFlags bool
}

Using this approach you can separate commands' flags parsing from the execution.

Maxim
  • 514
  • 2
  • 7