The
I’ve also set the value of an environment variable
Into your work directory (
1.
2.
* the file name has to end with
* the package name has to be the same as in the source file that has to be tested
* you have to import the package
* all test functions should start with
* the tests will be executed in the same order that they are appear in the source
* the test function
* the signature of the test function should always be
* a call to any of the following functions of
3.
If you haveall the three both files in place, you can run your tests by executing
rm -f _test/mylibpkg.a
rm -f _test/mylibpkg.a
gopack grc _test/mylibpkg.a _gotest_.6
--- FAIL: intpkg.Test_Add2Ints_2 (0.00 seconds)
this is just hardcoded as an error.
FAIL
exit status 1
FAIL trials/projtst 0.010s
Let us take a minute to analyze that output.
* the first 3 lines is some internal work done by the program recreate the package
* then there is the result of our hardcoded test fail in
* what happened to the first test? It was executed and it passed, so that is fine. But by default
* the last two lines is an overall status saying that not all tests passed.
* benchmark tests must have the signatureand the hyphen for the
* benchmark tests are not run by default by
* benchmark tests have to be specifically run by giving the command line option
* go test automatically figures out how long the test has to be run to get a reasonable benchmark result
* to make that work, use the field
* the performance is, I am assuming, from the time that the execution enters the Benchmark function until its exit
* if therefore, you are doing other tasks within the
Add a new file shown below.
Now we want to run only the tests in this new file, so execute
You should be able to see results similar to that shown below:
The results show that there were no regular
Go
installation that you have comes with a unit testing package called testing
and a tool called go test
that you can use to write unit tests. This unit testing framework, like frameworks in other languages, allow you to write any number of tests that you can run frequently to check the correctness of your code in small units. You can also write benchmark tests that you can use to check the performance of your functions. Writing and executing unit Tests
We shall create a separate directory to create and execute our trial testing code sincego test
works with all files in a directory. It is convenient as all packages usually have their own directory. For the purpose of this tutorial, I am calling my directory projtst
. $GOROOT
to where the go
SDK installation is - on my machine this is ~/coding/golang/go
. This will be useful later on as we have to access two files in the $GOROOT/src/
folder for inclusion in our Makefile
.Into your work directory (
projtst
for me, but the name does not matter), create the following three files: intlib.go, intlib_test.go, Makefile.1.
intlib.go
: this file contains a function that adds two integers and this is your source file.Full program - intlib.go
package intpkg func Add2Ints(i, j int) int { return i + j }
2.
intlib_test.go
: this file contains the tests that will be run. Please note the following with respect to this code:* the file name has to end with
_test.go
to be picked up as a set of tests by go test
* the package name has to be the same as in the source file that has to be tested
* you have to import the package
testing
* all test functions should start with
Test
to be run as a test* the tests will be executed in the same order that they are appear in the source
* the test function
TestXxx
functions take a pointer to the type testing.T
. You use it to record the test status and also for logging.* the signature of the test function should always be
func TestXxx ( *testing.T)
. You can have any combination of alphanumeric characters and the hyphen for the Xxx
part, the only constraint that it should not begin with a small alphabet, [a-z].* a call to any of the following functions of
testing.T
within the test code Error, Errorf, FailNow, Fatal, FatalIf
will indicate to go test
that the test has failed.Full program - intlib_test.go
package intpkg //same package name as source file import ( "testing" //import go package for testing related functionality ) func Test_Add2Ints_1(t *testing.T) { //test function starts with "Test" and takes a pointer to type testing.T if (Add2Ints(3, 4) != 7) { //try a unit test on function t.Error("Add2Ints did not work as expected.") // log error if it did not work as expected } else { t.Log("one test passed.") // log some info if you want } } func Test_Add2Ints_2(t *testing.T) { //test function starts with "Test" and takes a pointer to type testing.T t.Error("this is just hardcoded as an error.") //Indicate that this test failed and log the string as info }
Makefile
: go test
requires you to have a valid Makefile
that can be used to build the target.Full program - Makefile
# include this file which comes with go installation include ${GOROOT}/src/Make.inc TARG=mylibpkg # the *_test.go files are not to be included here. Only those your would use to build the actual program. go test will figure out the *_test.go files for itself. GOFILES=\ intlib.go\ # include this file which comes with go installation include ${GOROOT}/src/Make.pkg
If you have
go test
at the command line. The executable is in the bin
directory of your Go SDK installation. If it is not in your PATH
already, I would suggest you add it. The result of running executing go test
is shown below.rm -f _test/mylibpkg.a
gopack grc _test/mylibpkg.a _gotest_.6
this is just hardcoded as an error.
FAIL
exit status 1
FAIL trials/projtst 0.010s
Let us take a minute to analyze that output.
* the first 3 lines is some internal work done by the program recreate the package
* then there is the result of our hardcoded test fail in
Test_Add2Ints_2
* what happened to the first test? It was executed and it passed, so that is fine. But by default
go test
hides all passed results. If you want to see all results, including PASSed tests, execute it with the -v option thus: go test -v
.* the last two lines is an overall status saying that not all tests passed.
Writing and executing Benchmark tests
Benchmark tests allow you to check the performance of your code. A few things to note:* benchmark tests must have the signature
func BenchmarkXxx ( *testing.B)
. You can have any combination of alphanumeric characters Xxx
part, the only constraint that it should not begin with a small alphabet, [a-z]* benchmark tests are not run by default by
go test
* benchmark tests have to be specifically run by giving the command line option
-test.bench="test_name_regex"
or its equivalent -bench="test_name_regex"
. E.g. go test -bench=".*"
to run all benchmarks tests* go test automatically figures out how long the test has to be run to get a reasonable benchmark result
* to make that work, use the field
testing.B.N
within a loop to repeatedly run a certain function* the performance is, I am assuming, from the time that the execution enters the Benchmark function until its exit
* if therefore, you are doing other tasks within the
Benchmark
function, like time consuming initialization, this will give you incorrect benchmark results. In these instances, stop and start the timer by calling functions testing.B.StopTimer()
and testing.B.StartTimer()
as appropriate.Note: I discovered through time consuming trial and error that if any of the
TestXxx
functions fail, then the BenchmarkXxx
tests are either not run or its results are not displayed. Either ways, no benchmark results if all the unit tests do not pass successfully. So either make sure all tests pass successfully, which of course should be the plan in any case. But if you have failed tests and want to run benchmark tests, use the -file “filename"_test.go
to run the tests in just the specified file.Add a new file shown below.
Full program - intlib_b_test.go
package intpkg //same package name as source file import ( "testing" //import go package for testing related functionality ) func Benchmark_TheAddIntsFunction(b *testing.B) { //benchmark function starts with "Benchmark" and takes a pointer to type testing.B for i := 0; i < b.N; i++ { //use b.N for looping Add2Ints(4, 5) } } func Benchmark_TimeConsumingFunction(b *testing.B) { //benchmark function starts with "Benchmark" and takes a pointer to type testing.B b.StopTimer() //stop the performance timer temporarily while doing initialization //do any time consuming initialization functions here ... //database connection, reading files, network connection, etc. b.StartTimer() //restart timer for i := 0; i < b.N; i++ { Add2Ints(4, 5) } }
Now we want to run only the tests in this new file, so execute
go test
with the -file
option:go test -file intlib_b_test.go -bench=".*"
You should be able to see results similar to that shown below:
...
testing: warning: no tests to run
PASS
intpkg.Benchmark_TheAddIntsFunction 500000000 4.23 ns/op
intpkg.Benchmark_TimeConsumingFunction 500000000 4.26 ns/op
testing: warning: no tests to run
PASS
intpkg.Benchmark_TheAddIntsFunction 500000000 4.23 ns/op
intpkg.Benchmark_TimeConsumingFunction 500000000 4.26 ns/op
The results show that there were no regular
TestXxx
type of tests to run. The next two lines are the results of our benchmark tests. This one shows that the first function was run 500000000 times and each of them completed in an average time of 4.23 nanoseconds.
It seems that the command is now called "go test" and a makefile is no longer necessary in golang 1.0
ReplyDeleteHey oers, I know it's been some time but I've updated it now. Thank you.
DeleteNote, "the package name has to be the same as in the source file that has to be tested"
ReplyDeleteThat's actually not entirely true. You can label the tests as _test (even if they're in the same directory as the original package) and then they run as if they're outside the package (good for black box testing, and for examples with proper package.Name usage).
However, if you want to use unexported parts of the package, you do need the test to be in the same package.
Sorry, that should say package_test (I used brackets which evidently got stripped out).
Deleteit seems that -file is not used in go version 1.0.3
ReplyDeletei use the command:
go test -bench=".*" -v -file=intlib_b_test.go
it still run the
=== RUN Test_Add2Ints_1
--- PASS: Test_Add2Ints_1 (0.00 seconds)
intlib_test.go:11: one test passed.
=== RUN Test_Add2Ints_2
--- PASS: Test_Add2Ints_2 (0.00 seconds)
nice article
ReplyDelete