Golang Testing Technology

Source: Internet
Author: User
Tags response code starttls
This is a creation in Article, where the information may have evolved or changed.

This article is from the Golang core Development group Andrew Gerrand in the Google I/O 2014 theme Sharing "Testing techniques", that is, the use of Golang development using the test technology (mainly for unit testing), Including basic technology, advanced technology (concurrency test, mock/fake, competitive conditions test, concurrency test, internal/external testing, vet tools, etc.), and so on, the feeling summed up very comprehensive, here to record down, hope to bring you help. The original slide access needs to take his own ladder. Also here to spit Groove: Golang official station of the slide are in a unique Golang artical format released (with this tool http://go-talks.appspot.com/can be viewed online), can't download like a PDF, Domestic use and transmission are extremely inconvenient.

First, the basic testing technology

1. Test Go Code

Go language built-in test framework.

The built-in test framework provides test functionality through the testing package and go test commands.

The following is a complete test strings. Complete test file for the index function:

//strings_test.go (这里样例代码放入strings_test.go文件中) package strings_testimport ("strings""testing")func TestIndex(t *testing.T) {const s, sep, want = "chicken", "ken", 4got := strings.Index(s, sep)if got != want {    t.Errorf("Index(%q,%q) = %v; want %v", s, sep, got, want)//注意原slide中的got和want写反了}}

$go test-v Strings_test.go
= = = RUN Testindex
-pass:testindex (0.00 seconds)
PASS
OK command-line-arguments 0.007s

The-v option of Go test represents the verbose execution information for the output.

To modify the want constant value in code to 3, we create a test that cannot be passed:

$go test-v Strings_test.go
= = = RUN Testindex
-fail:testindex (0.00 seconds)

Strings_test.go:12:index ("Chicken", "ken") = 4; Want 3

FAIL
Exit Status 1
FAIL command-line-arguments 0.008s

2. Table-Driven test

Golang's struct literal (struct literals) syntax allows us to easily write table-driven tests.

package strings_testimport ("strings"    "testing")func TestIndex(t *testing.T) {var tests = []struct {            s   string            sep string            out int    }{            {"", "", 0},            {"", "a", -1},            {"fo", "foo", -1},            {"foo", "foo", 0},            {"oofofoofooo", "f", 2},            // etc    }    for _, test := range tests {            actual := strings.Index(test.s, test.sep)            if actual != test.out {                    t.Errorf("Index(%q,%q) = %v; want %v",                         test.s, test.sep, actual, test.out)            }    }}

$go test-v Strings_test.go
= = = RUN Testindex
-pass:testindex (0.00 seconds)
PASS
OK command-line-arguments 0.007s

3. T structure

*testing. The T parameter is used for error reporting:

T.errorf ("Got bar =%v, want%v", got, Want)
T.fatalf ("Frobnicate (%V) returned error:%v", ARG, err)
T.LOGF ("Iteration%v", i)

can also be used for enable parallel testing (Parallet test):
T.parallel ()

Controls whether a Test runs:

If runtime. Goarch = = "Arm" {t.skip ("This doesn ' t work on Arm")}

4. Run the test

We use the Go Test command to run a test for a specific package.

The default is to execute the test code for the package under the current path.

$ go Test
PASS

$ go test-v
= = = RUN Testindex
-pass:testindex (0.00 seconds)
PASS

To run all the tests under the project, we execute the following command:

$ go Test github.com/nf/...

Test of the standard library:
$ GO Test STD

Note: Assuming that the current directory of Strings_test.go is Testgo, executing go test in the Testgo directory is OK. But what happens if we switch to the top-level directory of Testgo to execute go test?

$go Test Testgo
Can ' t load package:package testgo:cannot Find package "Testgo" in any of:

/usr/local/go/src/pkg/testgo (from $GOROOT)/users/tony/test/gotoolsprojects/src/testgo (from $GOPATH)

Testgo This package is not found, the go test should be followed by a package name, and go test will find the package under Goroot and Gopath and execute the package tests.

5. Test coverage

The Go Tool command can report test coverage statistics.

We executed go test-cover under Testgo and the results were as follows:

Go build /users/tony/test/go/testgo:no buildable go source files In/users/tony/test/go/testgo
FAIL
/users/tony/test/go/testgo [build failed]

It is obvious that testing coverage by cover parameter options requires not only testing the code, but also the source file of the object being measured (usually the function).

We switch the directory to $goroot/src/pkg/strings and execute go test-cover:

$go test-v-cover
= = = RUN Testreader
-pass:testreader (0.00 seconds)
... ...
= = = Run:exampletrimprefix
-pass:exampletrimprefix (1.75us)
PASS
coverage:96.9% of statements
OK strings 0.612s

Go test can generate a profile of coverage, which can be parsed by the Go tool cover tools.

Execute under $goroot/src/pkg/strings:

$ go test-coverprofile=cover.out

The Cover.out file is then generated in the current directory.

There are two ways to view the Cover.out file:

A) cover-func=cover.out

$sudo Go Tool cover-func=cover.out
Strings/reader.go:24:len 66.7%
Strings/reader.go:31:read 100%
Strings/reader.go:44:readat 100%
Strings/reader.go:59:readbyte 100%
Strings/reader.go:69:unreadbyte 100%
... ...
Strings/strings.go:638:replace 100%
Strings/strings.go:674:equalfold 100%
Total: (statements) 96.9%

b) Visual view

Execute the Go tool cover-html=cover.out command to generate a directory coverxxxxxxx, such as/tmp/cover404256298, in the/tmp directory. There is a coverage.html file under the directory. Open coverage.html with a browser, which allows you to visualize the test coverage of your code.

On the Go tool's cover command, my go version go1.3 Darwin/amd64 is not brought by default and needs to be downloaded via go get.

$sudo gopath=/users/tony/test/gotoolsprojects Go get code.google.com/p/go.tools/cmd/cover

After downloading, cover is installed under $GOROOT/PKG/TOOL/DARWIN_AMD64.

Second, advanced testing technology

1. An example program

Outyet is a Web service that declares whether a particular go version has been tagged for publication. How to get it:

Go get Github.com/golang/example/outyet

Note:
After the go get executes, the CD $GOPATH/src/github.com/golang/example/outyet and executes go run main.go. The Web service can then be accessed by opening http://localhost:8080 in a browser.

2. Test HTTP client and server

The Net/http/httptest package provides a number of helper functions for testing code that sends or processes HTTP requests.

3, Httptest. Server

Httptest. Server listen on a system-selected port on the local loopback gateway. It is often used for end-to-end HTTP testing.

type Server struct {URL      string // base URL of form http://ipaddr:port with no trailing slashListener net.Listener// TLS is the optional TLS configuration, populated with a new config// after TLS is started. If set on an unstarted server before StartTLS// is called, existing fields are copied into the new config.TLS *tls.Config// Config may be changed after calling NewUnstartedServer and// before Start or StartTLS.Config *http.Server}func NewServer(handler http.Handler) *Serverfunc (*Server) Close() error

4, Httptest. Server combat

The following code creates a temporary HTTP Server that returns a simple Hello answer:

TS: = httptest. NewServer (http. Handlerfunc (Func (w http. Responsewriter, R *http. Request) {    fmt. Fprintln (W, "Hello, Client")}) defer TS. Close () res, err: = http. Get (TS. URL) If err! = Nil {    log. Fatal (Err)}greeting, err: = Ioutil. ReadAll (Res. Body) Res. Body.close () if err! = Nil {    log. Fatal (Err)}fmt. Printf ("%s", greeting)

5, Httptest. Responserecorder

Httptest. Responserecorder is an implementation of Http.responsewriter, used to record changes and used in subsequent inspections of tests.

type ResponseRecorder struct {Code      int           // the HTTP response code from WriteHeaderHeaderMap http.Header   // the HTTP response headersBody      *bytes.Buffer // if non-nil, the bytes.Buffer to append written data toFlushed   bool }

6, Httptest. Responserecorder Combat

A responserecorder is passed into an HTTP handler, through which we can view the generated response.

Handler: = Func (w http. Responsewriter, R *http. Request) {    http. Error (W, "Something Failed", http. Statusinternalservererror)}req, err: = http. Newrequest ("GET", "Http://example.com/foo", nil) if err! = Nil {    log. Fatal (err)}w: = Httptest. Newrecorder () Handler (W, req) fmt. Printf ("%d–%s", W.code, W.body.string ())

7. Competition detection (race detection)

Data contention occurs when two goroutine concurrently access the same variable, and at least one goroutine writes to the variable.

To assist in diagnosing this bug,go provides a built-in data competition detection tool.

With the incoming-race option, the Go tool can start competitive detection.

$ go test-race mypkg//To test the package
$ go run-race mysrc.go//To run the source file
$ go build-race mycmd//To build the command
$ go install-race mypkg//To install the package

Note: An example of a data competition test

Example code:

//testrace.gopackage mainimport “fmt” import “time”func main() {var i int = 0    go func() {            for {                    i++                    fmt.Println("subroutine: i = ", i)                    time.Sleep(1 * time.Second)            }    }()    for {            i++            fmt.Println("mainroutine: i = ", i)            time.Sleep(1 * time.Second)    }}

$go Run-race Testrace.go

MAINROUTINE:I = 1

Warning:data RACE
Read by Goroutine 5:
Main.func 001 ()

/users/tony/test/go/testrace.go:10 +0x49

Previous Write by main goroutine:
Main.main ()

/users/tony/test/go/testrace.go:17 +0xd5

Goroutine 5 (running) created at:
Main.main ()

/users/tony/test/go/testrace.go:14 +0xaf

==================
SUBROUTINE:I = 2
MAINROUTINE:I = 3
SUBROUTINE:I = 4
MAINROUTINE:I = 5
SUBROUTINE:I = 6
MAINROUTINE:I = 7
SUBROUTINE:I = 8

8. Test concurrency (testing with concurrency)

When testing concurrent code, there is always an impulse to use sleep. For most of the time, using sleep is both simple and effective.

But most of the time is not "always".

We can use the concurrency primitives of go to make the tests that are strange and unreliable sleep drivers more trustworthy.

9. Use static analysis tool vet to find errors

The Vet tool is used to detect common mistakes programmers make in code:

– Wrong printf format – wrong build tag– using wrong range loop variable in closures – useless assignment operation – Code unreachable – Error using mutex, etc.

How to use:

Go vet [Package]

10, from the internal testing

Most of the test code in Golang is part of the source of the package being tested. This means that the test code can access symbols that are not exported by the package and internal logic. Just like we saw before.

Note: $goroot/src/pkg/path/path_test.go and path.go, for example, are under the package path.

11, from the external testing

In some cases, you need to test the package from the outside of the package, such as the test code under the packages Foo_test, rather than the packages foo.

This can break the dependency cycle, such as:

The test code for the –testing package that uses the FMT–FMT package must also be imported into the testing package – so the test code for the FMT package is placed under the Fmt_test package so that either the testing package can be imported or the FMT package can be imported at the same time.

12, mocks and fakes

You can avoid using mock and fake test mechanisms by using Interface,go in your code.

For example, if you are writing a file format parser, do not design functions like this:

Func Parser (f *os. File) Error

Instead, you can write a function that accepts the interface type:

Func Parser (R io. Reader) Error

and bytes. Buffer, Strings. Like reader, *os. File also implements the Io.reader interface.

13. Sub-process Testing

There are times when you need to test the behavior of a process, not just a function. For example:

func Crasher() {fmt.Println("Going down in flames!")os.Exit(1)}

To test the code above, we tested the test program itself as a child process:

func TestCrasher(t *testing.T) {if os.Getenv("BE_CRASHER") == "1" {    Crasher()    return}cmd := exec.Command(os.Args[0], "-test.run=TestCrasher")cmd.Env = append(os.Environ(), "BE_CRASHER=1")err := cmd.Run()if e, ok := err.(*exec.ExitError); ok && !e.Success() {    return}t.Fatalf("process ran with err %v, want exit status 1", err)}

, Bigwhite. All rights reserved.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.