257 lines
9.5 KiB
Markdown
257 lines
9.5 KiB
Markdown
# Running and Writing Tests for Sia
|
|
Improving test coverage is a great way to start contributing to Sia.
|
|
|
|
This guide focuses on how to write tests. To learn about making pull requests
|
|
to submit the code you've written, see
|
|
[doc/Guide to Contributing to Sia.md][guide]. You should also read
|
|
[doc/Developers.md][developers] to learn about Sia code conventions and quality
|
|
standards.
|
|
|
|
|
|
#### Table of Contents
|
|
* [Running tests for Sia](#existing)
|
|
* [Updating code before testing](#update)
|
|
* [Testing the entire build](#entire)
|
|
* [Testing a particular package](#particular)
|
|
* [Writing new tests for Sia](#write)
|
|
* [A few guidelines](#naming)
|
|
* [Basic test format](#basic)
|
|
* [Table-driven tests](#table)
|
|
* [Questions?](#questions)
|
|
|
|
<a name="existing"/>
|
|
## Running tests for Sia
|
|
Go's comprehensive [test package][pkg/testing] makes testing straightforward,
|
|
particularly when you use the bundled tools included in the
|
|
[Sia makefile][makefile], including `make test`, `make cover`, `make bench`,
|
|
and their variants.
|
|
|
|
<a name="update"/>
|
|
### Updating code before testing
|
|
If you just want to run existing tests on the codebase as is, you just need to
|
|
pull the latest version of the original repo to your master branch. (If that
|
|
sentence didn't make sense, go read
|
|
[doc/Guide to Contributing to Sia.md][guide].)
|
|
|
|
```bash
|
|
# Make sure you are in the right directory.
|
|
$ cd $GOPATH/src/github.com/<your Github username>/Sia
|
|
# Also make sure you're working with the right branch.
|
|
$ git checkout master
|
|
# Pull latest changes from origin, the original Sia repo.
|
|
$ git pull origin master
|
|
# Update your fork of the repo, which should be set up as a remote.
|
|
$ git push <remote> master
|
|
```
|
|
|
|
If you want to run tests on the new code you've added, first make sure the rest
|
|
of the code is up to date. New code should be on its own branch (again, see
|
|
[doc/Guide to Contributing to Sia.md][guide]).
|
|
|
|
```bash
|
|
# Make sure you are in the right directory.
|
|
$ cd $GOPATH/src/github.com/<your Github username>/Sia
|
|
# Checkout the branch you made the changes on.
|
|
$ git checkout <branch name>
|
|
# Stash any tracked but uncommitted changes.
|
|
$ git stash
|
|
# Then switch back to `master` and update it to match the original repo.
|
|
$ git checkout master
|
|
$ git pull origin master
|
|
# Update your fork of the repo, which you should have set up as a remote.
|
|
$ git push <remote> master
|
|
# Make the updated `master` the new base of the branch you made the changes on,
|
|
# which involves reapplying all the commits made to that branch. Without the
|
|
# `--ignore-date` flag, git rebase changes the date on all the commits to the
|
|
# current date.
|
|
$ git checkout <branch name>
|
|
$ git rebase master --ignore-date
|
|
# Restore the changes you stashed earlier.
|
|
$ git stash pop
|
|
```
|
|
When you call `rebase`, you may run into some merge conflicts. Luke Champine's
|
|
['How to into git and GitHub'][luke] has more details (and many useful tricks).
|
|
|
|
Once the branch you want to test is up to date, you're ready to run some tests.
|
|
|
|
<a name="entire"/>
|
|
### Testing the entire build
|
|
The `make test` command runs all tests (functions starting with `Test` in
|
|
`_test.go` files) for each package, setting off a panic for any test that runs
|
|
longer than 5s. For verbose output, run `make test-v` (which panics after 15s
|
|
instead of 5s). Finally, `make test-long` has verbose output, only panics when
|
|
a test takes 5 minutes, and also cleans up your code using `gofmt` and `golint`.
|
|
**You should run** `make test-long` **before each pull request.**
|
|
|
|
Run `make cover` to run all tests for each package and generate color-coded
|
|
.html visualizations of test coverage by function for each source file. Open
|
|
`cover/<module>.html` in a browser to inspect a module's test coverage. For
|
|
example, here's part of the html file generated for the persist package:
|
|
|
|

|
|
|
|
Meanwhile, `make bench` will call `gofmt` on all packages, then run all
|
|
benchmarks (functions starting with `Benchmark` in `_test.go` files).
|
|
|
|
<a name="particular"/>
|
|
### Testing a particular package or function
|
|
To run tests for just a certain package, run `make test pkgs=./<package>`. To run
|
|
a certain test function, run `make test pkgs=./<package> run=<function>`. The same
|
|
goes for `make test-long`, `make cover` and `make bench`.
|
|
|
|
For example, running `test-long` on the package persist produces this output:
|
|
|
|
```bash
|
|
$ make test-long pkgs=./persist
|
|
rm -rf release doc/whitepaper.aux doc/whitepaper.log doc/whitepaper.pdf
|
|
gofmt -s -l -w ./persist
|
|
go install ./persist
|
|
go vet ./persist
|
|
go test -v -race -tags='testing debug' -timeout=300s ./persist -run=Test
|
|
=== RUN TestOpenDatabase
|
|
--- PASS: TestOpenDatabase (0.42s)
|
|
=== RUN TestSaveLoad
|
|
--- PASS: TestSaveLoad (0.00s)
|
|
=== RUN TestSaveLoadFile
|
|
--- PASS: TestSaveLoadFile (0.01s)
|
|
=== RUN TestSaveLoadFileSync
|
|
--- PASS: TestSaveLoadFileSync (0.00s)
|
|
=== RUN TestLogger
|
|
--- PASS: TestLogger (0.00s)
|
|
=== RUN TestLoggerCritical
|
|
--- PASS: TestLoggerCritical (0.00s)
|
|
=== RUN TestIntegrationRandomSuffix
|
|
--- PASS: TestIntegrationRandomSuffix (0.01s)
|
|
=== RUN TestAbsolutePathSafeFile
|
|
--- PASS: TestAbsolutePathSafeFile (0.00s)
|
|
=== RUN TestRelativePathSafeFile
|
|
--- PASS: TestRelativePathSafeFile (0.00s)
|
|
PASS
|
|
ok github.com/NebulousLabs/Sia/persist 1.485s
|
|
$
|
|
```
|
|
|
|
<a name="write"/>
|
|
## Writing new tests for Sia
|
|
When you run `make cover`, you'll notice that many files have pretty low
|
|
coverage. We're working on fixing that, but we could use your help.
|
|
|
|
<a name="naming"/>
|
|
### A few guidelines
|
|
* The test functions for `filename.go` should go in `filename_test.go` in the
|
|
same directory and package.
|
|
* A test function name should start with `Test` and clearly convey what is
|
|
being tested.
|
|
* You should declare function-specific variables and constants locally (inside
|
|
the test function) instead of globally (outside the test function). [That
|
|
holds in general][global], not just for tests.
|
|
* As always, code should adhere to the standards and conventions laid out in
|
|
[doc/Developers.md][developers].
|
|
|
|
<a name="basic"/>
|
|
### Basic test format
|
|
Suppose we'd like to test the Bar method belonging to type Foo.
|
|
|
|
```go
|
|
// TestFoo checks that the Bar method on type Foo responds correctly to a normal
|
|
// input and returns the expected error when given a bad input.
|
|
func TestFoo(t *testing.T) {
|
|
foo, err := NewFoo()
|
|
if err != nil {
|
|
// If NewFoo failed, we can't continue testing.
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Try a normal input; should succeed.
|
|
err := foo.Bar(3)
|
|
if err != nil {
|
|
// Report the error, but don't abort the test.
|
|
t.Error(err)
|
|
}
|
|
|
|
// Try a bad input; should return an error.
|
|
// NOTE: Always prefer to compare to a specific error, rather than
|
|
// err == nil
|
|
err = Foo.Bar(0)
|
|
if err != errDivideByZero {
|
|
t.Errorf("expected errDivideByZero, got %v", err)
|
|
}
|
|
}
|
|
|
|
```
|
|
|
|
<a name="table"/>
|
|
### Table-driven tests in Go
|
|
If you're looking to test a bunch of inputs, write a [table-driven test][table]
|
|
with a slice of anonymous structs. For example, see `TestParseFileSize` in
|
|
[siac/parse_test.go][parse_test]:
|
|
|
|
```go
|
|
func TestParseFilesize(t *testing.T) {
|
|
// Define a table of test cases in the form of a slice of anonymous structs.
|
|
tests := []struct {
|
|
in, out string
|
|
err error
|
|
}{
|
|
{"1b", "1", nil},
|
|
{"1KB", "1000", nil},
|
|
{"1MB", "1000000", nil},
|
|
{"1GB", "1000000000", nil},
|
|
{"1TB", "1000000000000", nil},
|
|
{"1KiB", "1024", nil},
|
|
{"1MiB", "1048576", nil},
|
|
{"1GiB", "1073741824", nil},
|
|
{"1TiB", "1099511627776", nil},
|
|
{"", "", errUnableToParseSize},
|
|
{"123", "123", nil},
|
|
{"123TB", "123000000000000", nil},
|
|
{"123GiB", "132070244352", nil},
|
|
{"123BiB", "", errUnableToParseSize},
|
|
{"GB", "", errUnableToParseSize},
|
|
{"123G", "", errUnableToParseSize},
|
|
{"123B99", "", errUnableToParseSize},
|
|
{"12A3456", "", errUnableToParseSize},
|
|
{"1.23KB", "1230", nil},
|
|
{"1.234KB", "1234", nil},
|
|
{"1.2345KB", "1234", nil},
|
|
}
|
|
// Loop through the table of test cases to make sure ParseFileSize returns
|
|
// the expected output and error for each.
|
|
for _, test := range tests {
|
|
res, err := parseFilesize(test.in)
|
|
if res != test.out || err != test.err {
|
|
t.Errorf("parseFilesize(%v): expected %v %v, got %v %v", test.in, test.out, test.err, res, err)
|
|
}
|
|
}
|
|
}
|
|
```
|
|
<a name="questions"/>
|
|
## Questions?
|
|
Read these if you haven't already:
|
|
* [doc/Guide to Contributing to Sia.md][guide]: getting started with Go, Sia,
|
|
and git
|
|
* [doc/Developers.md][developers]: conventions and quality standards for Sia
|
|
code
|
|
|
|
Some other useful resources, some of which have been linked to already:
|
|
* [Golang.org page on the go testing package][pkg/testing]
|
|
* [Writing Table-Driven Tests in Go][table]
|
|
* [How to Write Benchmarks in Go][cheney-benchmarks]
|
|
* [How to into git and GitHub][luke]: an essential introduction to git
|
|
|
|
And feel free to ask questions on the [#dev channel][slack] on the Sia Slack.
|
|
Odds are, someone else is wondering the same thing.
|
|
|
|
[pkg/testing]: https://golang.org/pkg/testing/
|
|
[makefile]: https://github.com/NebulousLabs/Sia/blob/master/Makefile
|
|
[luke]: https://gist.github.com/lukechampine/6418449
|
|
[guide]: https://github.com/NebulousLabs/Sia/blob/master/doc/Guide%20to%20Contributing%20to%20Sia.md
|
|
[developers]: https://github.com/NebulousLabs/Sia/blob/master/doc/Developers.md
|
|
[table]: http://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go
|
|
[boltdb_test.go]: https://github.com/NebulousLabs/Sia/blob/master/persist/boltdb_test.go
|
|
[cheney-benchmarks]: http://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go
|
|
[pkg/testing]: https://golang.org/pkg/testing/
|
|
[slack]: https://siatalk.slack.com/messages/dev/
|
|
[parse_test]: https://github.com/NebulousLabs/Sia/blob/master/siac/parse_test.go
|
|
[global]: http://c2.com/cgi/wiki?GlobalVariablesAreBad
|