Which methodology i should use to test func main() in golang?

I have a function main() in main.go that does the job. and all other functions below it (i did not include them here). So, when i write tests for all funcs that are included in the main, I can test them OK. But still the code coverage is low because it shows that i did not cover code from my main func.

I know that there is a TestMain func in testing library that should do the job, but i just cannot get how to get it working so that the test covers func main() code.

Below is my main() func which is not covered by tests...

func main() {
c, err := getConfig()
if err != nil {
    log.Fatal(err)
}
slideshows, err := getSlideshows(c)
if err != nil {
    log.Fatal(err)
}

displaySlideshows(slideshows)

}

Also, i did not find much about it in the internet, so, if this is really a stupid question, please, explain me why this is such a dum problem and where should i search for solutions!

Will much appreciate any help!

1 answer

  • answered 2018-07-11 04:31 VonC

    You can check out "Go coverage with external tests", by Filippo Valsorda:

    We create a dummy test that executes main(), we put it behind a build tag, compile a binary with go test -c -cover and then run only that test instead of running the regular binary.

    Here's what the rrdns_test.go file looks like:

    Note the empty line between the build tag and package:

    // +build testrunmain
    
    package main
    
    import "testing"
    
    func TestRunMain(t *testing.T) {
        main()
    }
    

    We compile the binary like this:

    $ go test -coverpkg="rrdns/..." -c -tags testrunmain rrdns
    

    And then when we want to collect coverage information, we execute this instead of ./rrdns (and run our test battery as usual):

    $ ./rrdns.test -test.run "^TestRunMain$" -test.coverprofile=system.out
    

    You must return from main() cleanly for the profile to be written to disk; in RRDNS we do that by catching SIGINT. You can still use command line arguments and standard input normally, just note that you will get two lines of extra output from the test framework.

    This is similar to this answer which proposes:

    func main() {
        os.Exit(doFunc());
    }