How to write unit tests under Golang? The official testing package is a little rough, but fortunately we have Gocheck.

What is a good unit test?

Before get into the business to review previous summarizes several principles of unit testing: www.atatech.org/articles/25…

Unit tests should verify the correctness of the program at the lowest functions/parameters... After the unit test, the machine state remains unchanged... 6 Independence. The running/passing/failure of a unit test is independent of other tests. Data can be artificially constructed to maintain the independence of the unit test.Copy the code

Good unit testing should follow these principles; A good unit testing framework should make it easy to practice these principles.

Gocheck is easy to use

Gocheck’s official website: labix.org/gocheck

Golang’s official Testing package is pretty weak: it doesn’t even support Assert. Gocheck adds functionality to the Testing library, taking us away from the endless “if… The else…” This suffering. Especially useful features include:

  1. Assert assertions + rich judgment verbs: deep multi-type comparison, string comparison (even regular matching supported!) .
  2. Organize test cases by suite, supporting suite level setup() and teardown().
  3. Create and delete temporary files/directories.

Example 1: Unit tests related to file operations

The “machine state stays the same after the unit test” principle tells us that if the unit test reads and writes files, the temporary files created should be cleaned up after the unit test.

Gocheck creates a temporary directory and automatically deletes it at the end of the test, eliminating manual cleanup.

Example:

package hello_test import ( "testing" "io/ioutil" "io" . "gopkg.in/check.v1" ) const txt = "adfagaggafaf" // Hook up Gocheck into the "go test" runner. Func test (t *testing.T) {TestingT(t)} type MySuite struct {dir string temporary directory for testing Func (s *MySuite) Setupsuite (c * c) {dir :=. Func (s *MySuite) Setupsuite (c * c) {dir := C. mkdir () // Suite will automatically destroy the directory created by c. mkdir () tmpFile, err := ioutil.tempFile (dir, "") if err! = nil { c.Errorf("Fail to create test file: %v\n", tmpfile.Name(), err) } err = WriteFile(tmpfile.Name(), txt) if err ! = nil { c.Errorf("Fail to prepare test file.%v\n", tmpfile.Name(), err) } s.dir = dir s.f = tmpfile.Name() } func (s *MySuite) TestFoo(c *C) { // ... Actual test code c.assert (bkpName, Matches, s.f+".ops_AGENT_bkp.+")}Copy the code

Example 2: Mock Web API-related unit tests

The principle of “independence” tells us that it is best to mock data for functions that require calls to external apis. Using goCheck’s SetUpSuite() and TearDownSuite() methods, you can create a new HTTP Test Server and close it at the end.

Example:

package hello_test import ( "fmt" "net/http" "net/http/httptest" "testing" . "gopkg.in/check.v1" ) const ( resp1 = `{ "data" : { "cluster" : "*****", "hostname" : "xxxxx" }, "err_code" : 0, "err_msg" : "" } ` resp2 = `{ "data" : [{" hostname ":" e18h13551. XXX ", "IP" : "100.22.33.44", "state" : "GOOD"}, {" hostname ":" DDDD ", "IP" : "101.14.12.55", "state" : "GOOD"}], "err_code" : 0, "err_msg" : "" } ` ) // Hook up gocheck into the "go test" runner. func Test(t *testing.T) { TestingT(t) } type MySuite struct { ts *httptest.Server } func (s *MySuite) SetUpSuite(c *C) { h := http.NewServeMux() h.HandleFunc("/machine", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, resp1) }) h.HandleFunc("/batch", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, resp2) }) s.ts = httptest.NewServer(h) } func (s *MySuite) TearDownSuite(c *C) { s.ts.Close() } var _ = Func (s *MySuite) TestFoo(c * c) {// Actual test code.... clusterName, err := getClusterName(s.ts.URL, "/machine") c.Assert(err, IsNil) c.Assert(clusterName, Equals, "MiniLVSCluster-5e87-2384205713506559") }Copy the code

other

Gocheck’s other useful features, such as the powerful Checker, are not listed here. You can browse the website to make writing unit tests easier.