-
Notifications
You must be signed in to change notification settings - Fork 1
/
testing.slide
204 lines (140 loc) · 5.87 KB
/
testing.slide
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
Advanced testing techniques
Tips and tricks for testing
20 Jan 2010
Tags: test, mock
Tiago Queiroz
Principal Backend Engineer, Onefootball
https://github.com/belimawr
@belimawr_
* Who am I?
- Brazilian
- 6+ years of professional experience
- 3+ years working with golang
- Worked with different technologies: Golang, Python, Java/Kotlin, C/C++, etc
- I love Golang
- I love tests
- I'm bad at making "who am I slides"
- And also bad at making jokes
* Agenda
- Mocks
- Unit x Integration test
- Concurrent tests
- Test cache
- Tips and tricks
.image qr_code.png 259 200
* Mocks
* Mocks
- Fake object used in tests to simulate a specific behaviour and assert if some conditions are met:
- Parameters are passed with the correct values
- Methods are called/how many times are called
- Methods are called in the correct order
- etc.
- Given the *Cache* interface
.code examples/cache/cache.go /START-CACHE OMIT/,/END-CACHE OMIT/
* Mocks
We can easily implement a mock (*mocks.go*):
.code examples/cache/mocks.go /START-CACHE-MOCK OMIT/,/END-CACHE-MOCK OMIT/
* Mocks
And use it:
.code examples/cache/cache_test.go /START-CACHE-EX1 OMIT/,/END-CACHE-EX1 OMIT/
* Mocks
We can even do assertions:
.code examples/cache/cache_test.go /START-CACHE-EX2 OMIT/,/END-CACHE-EX2 OMIT/
* Mocks
With a small change to our mock we can count function calls:
.code examples/cache/mocks.go /START-CACHE-MOCK2 OMIT/,/END-CACHE-MOCK2 OMIT/
* Mocks
Asserting how many times a function was called is easy:
.code examples/cache/cache_test.go /START-CACHE-EX3 OMIT/,/END-CACHE-EX3 OMIT/
* Unit x Integration test
* Unit x Integration test
For the purpose of this talk, let's stick with a very simplistic definition:
- *Unit*Test:* Any kind of test that depends only on your testing binary (a.k.a.: your code and its dependencies)
- *Integration*Test:* Any kind of test that has got external dependencies like: databases, APIs, docker, anything external to your testing binary/code.
Our goal: using only `go`test`, find a easy way to flag which kind of test we want to run, and do any kind of mix-and-match between them
* Unit x Integration test
The solution is simple: *build*tags*!
Normal unit test:
.code examples/build_flags/unit_test.go
Integration test:
.code examples/build_flags/integration_test.go
Postgres test:
.code examples/build_flags/postgres_test.go
* Unit x Integration test, Show me the code!
Normal unit tests:
go test -v ./...
Integration tests:
go test -v -tags=integration ./...
Postgres tests:
go test -v -tags=integration,postgres ./...
Bonus! Only short tests
go test -v -short ./...
* Unit x Integration test: short tests
This requires a bit of coding
.code examples/build_flags/short_test.go
* Running tests in parallel
* Running tests in parallel
Golang supports running tests of the same package in parallel, all you need is to add `t.Parallel()` to your tests.
.code examples/concurrency/concurrency_test.go /START OMIT/,/END OMIT/
* Running tests in parallel
It also works with sub-tests:
.code examples/concurrency/concurrency_test.go /START-TABLE OMIT/,/END-TABLE OMIT/
* Running tests & cache
* ex01.sh
.code ex01.sh /START OMIT/,/END OMIT/
* Test Cache
- Speeds up development, as you have a faster feedback loop
- Quite bad if you have intermittent failures
- Simple to solve (ex02.sh):
.code ex02.sh /START OMIT/,/END OMIT/
* Tips and tricks
* Test failure messages
- First thing we see when the test fails
- Should provide enough information about *why* the test failed
- Should provide enough information to *reproduce* *the* *failure*
- If using a RNG, every test can use a random seed, and in case of failure, log the seed
: RNG can use random seeds and log the seeds on failures
: Tests should be as random as possible, as close as possible to production environments
*Bad:*
t.Error("got the wrong value")
*Good:*
// some test code
t.Errorf("expecting: 42, got: %d", v)
* Even better
expected := 42
// some testing code
v := doStuff()
if v != expected {
t.Errorf("expecting: %d, got: %d", expected, v)
}
* Helper functions (and test data)
.code -numbers examples/helper/helper_test.go /START-LoadJSON OMIT/,/END-LoadJSON OMIT/
.code -numbers examples/helper/helper_test.go /START OMIT/,/END OMIT/
--- FAIL: TestFooBarError (0.00s)
helper_test.go:52: open testdata/ok: no such file or directory
* A better way
.code -numbers examples/helper/helper_test.go /START-LoadJSON2 OMIT/,/END-LoadJSON2 OMIT/
.code -numbers examples/helper/helper_test.go /START2 OMIT/,/END2 OMIT/
--- FAIL: TestFooBarError2 (0.00s)
helper_test.go:38: open testdata/ok: no such file or directory
* A few more things
- Test packages have the format: `<package_name>_test` (this is an exception to the "one package per folder")
- To store test data use the: `testdata` folder. It is ignored by the go tool
- Directories and files starting with `.` or `_` are also ignored by the go tool
- The current directory is always set to the folder where the `*_test.go` file is, not the one you called `go test`
- Each package is compiled individually and can run concurrently
* Useful packages for mocking dependencies
- HTTP: https://golang.org/pkg/net/http/httptest/
- SQL: https://github.com/DATA-DOG/go-sqlmock
- Redis (in-memory implementation): https://github.com/alicebob/miniredis
- Test runner with web UI: https://github.com/smartystreets/goconvey (I only use it to run the tests and see the coverage in the web UI)
* References (some of them)
- Gophercon UK: Advanced @ https://www.gopherguides.com/
- https://golang.org/cmd/go/#hdr-Description_of_package_lists
- http://peter.bourgon.org/go-in-production/#testing-and-validation
- https://dave.cheney.net/2013/10/12/how-to-use-conditional-compilation-with-the-go-build-tool
- https://changelog.com/gotime/101
- https://medium.com/@povilasve/go-advanced-tips-tricks-a872503ac859
* Questions?
.image qr_code.png 519 400