5 simple tips and tricks for writing unit tests in #golang
5 simple tips and tricks for writing unit tests in #golang
Test-driven development is a great way to keep the quality of your code high, while protecting yourself from regression and proving to yourself and others that your code does what it is supposed to.
Here are five tips and tricks that can improve your tests.
1. Put your tests in a different package
Go insists that files in the same folder belong to the same package, that is except for `_test.go` files. Moving your test code out of the package allows you to write tests as though you were a real user of the package. You cannot fiddle around with the internals, instead you focus on the exposed interface and are always thinking about any noise that you might be adding to your API.
This frees you up to change the internals however you like without having to adjust your test code.
2. Internal tests go in a different file
If you do need to unit test some internals, create another file with `_internal_test.go` as the suffix. Internal tests will necessarily be more brittle than your interface tests — but they’re a great way to ensure internal components are behaving, and are especially useful if you do test-driven development.
3. Run all tests on save
Go builds and runs very quickly, so there’s little to no reason why you shouldn’t run your entire test suite every time you hit save.
While you’re at it, why not run go vet, golint and goimports at the same time?
In Sublime Text, this can be acheived by installing GoSublime and hitting `Cmd+.,5` before adding the following configuration items:
“on_save”: [{
“cmd”: “gs9o_run_many”, “args”: {
“commands”:[
[“clear”],
[“sh”, “if [ -f onsave.sh ]; then ./onsave.sh; else gofmt -s -w ./ && go build . errors && go test -i && go test && go vet && golint ; fi”]
],
“focus_view”: false
}
}],
“fmt_cmd”: [“goimports”]
The above script first checks to see if the project has an `onsave.sh` file, which it will run instead. This allows you to easily turn off the auto-test feature for packages where it is not appropriate.
4. Write table driven tests
Anonymous structs and composite literals allow us to write very clear and simple table tests without relying on any external package.
The following code allows us to setup a range of tests for an as-yet unwritten `Fib` function:
var fibTests = []struct {
n int // input
expected int // expected result
}{
{1, 1},
{2, 1},
{3, 2},
{4, 3},
{5, 5},
{6, 8},
{7, 13},
}
Then our test function just ranges over the slice, calling the `Fib` method for each `n`, before asserting that the results are correct:
func TestFib(t *testing.T) {
for _, tt := range fibTests {
actual := Fib(tt.n)
if actual != tt.expected {
t.Errorf("Fib(%d): expected %d, actual %d", tt.n, tt.expected, actual)
}
}
}
See if you can write the `Fib` function yourself to make the tests pass or you can get the answer from Dave Chaney.
5. Mock things using Go code
If you need to mock something that your code relies on in order to properly test it, chances are it is a good candidate for an interface. Even if you’re relying on an external package that you cannot change, your code can still take an interface that the external types will satisfy.
After a few years of writing mocks, I have finally found the perfect way of mocking interfaces, and I made a tool write the code for us without us having to add any dependencies to our project: Check out Moq.
Let’s say we’re importing this external package:
package mailman
import “net/mail”
type MailMan struct{}
func (m *MailMan) Send(subject, body string, to ...*mail.Address) {
// some code
}
func New() *MailMan {
return &MailMan{}
}
If the code we’re testing takes a `MailMan` object, the only way our test code can call it is by providing an actual `MailMan` instance.
func SendWelcomeEmail(m *MailMan, to ...*mail.Address) {...}
This means that whenever we run our tests, a real email could be sent. Imagine if we’ve implemented the on save feature from above. We’d quickly annoy our test users or run up big service bills.
An alternative is to add this simple interface to your code:
type EmailSender interface{
Send(subject, body string, to ...*mail.Address)
}
Of course, the `MailMan` already satisfies this interface since we took the `Send` method signature from him in the first place — so we can still pass in `MailMan` objects as before.
But now we can write a test email sender:
type testEmailSender struct{
lastSubject string
lastBody string
lastTo []*mail.Address
}
// make sure it satisfies the interface
var _ package.EmailSender = (*testEmailSender)(nil)
func (t *testEmailSender) Send(subject, body string, to ...*mail.Address) {
t.lastSubject = subject
t.lastBody = body
t.lastTo = to
}
Now we can update our `SendWelcomeEmail` function to take the interface, rather than the concrete type:
func SendWelcomeEmail(m EmailSender, to ...*mail.Address) {...}
In our test code, we can send in our fake sender instead and make assertions on the fields after calling the target function:
func TestSendWelcomeEmail(t *testing.T) {
sender := &testEmailSender{}
SendWelcomeEmail(sender, to1, to2)
if sender.lastSubject != "Welcome" {
t.Error("Subject line was wrong")
}
if sender.To[0] != to1 && sender.To[1] != to2 {
t.Error("Wrong recipients")
}
}
- If you want to explore mocking further, then be sure to check out the Moq tool — not only does it describe a great way of writing mocks, it also writes them for you.
Treat yourself and your brain: Go Programming Blueprints
Build real tools, apps and services while exploring good practices in Go.
Go Programming Blueprints: Second Edition
相關推薦
5 simple tips and tricks for writing unit tests in #golang
5 simple tips and tricks for writing unit tests in #golangTest-driven development is a great way to keep the quality of your code high, while protecting yo
Tips and Tricks for Debugging in chrome
Tips and Tricks for Debugging in chrome Pretty print On sources panel ,clicking on the {} on the bottom left hand side. Console.table Display data as a
Ask HN: What is your best web browsing tips and tricks for non
Things like inspecting elements, custom chrome search engines etc. What are some things that you do with a browser to increase your productivity that non-d
LLVM Debugging Tips and Tricks
Back when I was working heavily with LLVM, I learned a bunch of little tricks that made my life so much easier. I meant to document them b
Git Tips and Tricks
Git Tips and TricksWhen I think about Git, I think about it as a time capsule one can travel with at a specific point of time in the source code history. E
Check out these useful ECMAScript 2015 (ES6) tips and tricks
Check out these useful ECMAScript 2015 (ES6) tips and tricksEcmaScript 2015 (aka ES6) has been around for couple of years now, and various new features can
10 Tips for Writing Better Code (閱讀理解)
存在 int 範圍 ide ready 有一個 不清晰 and app 出發點 http://www.tuicool.com/articles/A7VrE33 閱讀中文版本《編寫質優代碼的十個技巧》,對於我編碼十年的經驗,也有相同感受, 太多的坑趟過,太多的經歷走過,
ROS學習 Writing a Simple Publisher and Subscriber & Examining them
Go got pub sco targe ide 代碼 int pie 本文主要部分全部來源於ROS官網的Tutorials. 創建Publisher Node roscd beginner_tutorials mkdir -p src gedit src/talker.
Top 5 Java 8 and 9 Courses for Programmers (FREE)
Hello guys, if you are looking for some free resources e.g. books, tutorials and courses to learn and master new features introduced in Java 8 and Java 9
Top 5 IntelliJ IDEA and Android Studio Courses for Java and Android Development
There is no doubt that IntelliJ IDEA is THE best IDE for Java development, even though Eclipse may still be probably used by more people because it's FREE
Top 5 Database design and Modelling Books for Programmers and DBAs of All level
The database design and modeling are one of those topics which rarely gets the attention they deserve, especially at the start of the project, but once th
Top 5 Java Multithreading and Concurrency Courses for Experienced Programmers
If you are a Java developer and looking for some awesome resources e.g. books and courses to improve your multi-threading and concurrency skills in Java t
Top 5 Data Structures and Algorithm Online Courses for Java, JavaScript, and Python Programmers
Data Structure and Algorithm is one of the most important topics for programmers. The best thing about them is that they never get out-of-date and any inv
Linux下使用vi新建文件保存文件時遇到錯誤:E212: Can't open file for writing
mage images roo .cn logs 分享 思路 操作 新建 出現E212: Can‘t open file for writing的問題是由於權限問題導致的,解決方法有以下思路: 1、使用root進行登錄,然後再操作。 2、在使用命令時,前面加sudo
Victor 串口控件 1.5.0.6 VCL/FMX for C++ Builder 10.2 Tokyo, 10.1 Berlin, 10.0 Seattle, XE8, XE7, XE6 已經發布
blank sms mac 使用 模板 www 文本 clas stat Victor 串口控件 1.5.0.6 更新內容: ? 增加支持 FMX (Firemonkey) Win32/Win64,控件包含 VCL 和 FMX 兩個框架版本的,可以同時安裝 ? 增加
集合and增強for循環
oar ews 存儲 clas tid mov object pac 高考 package zxd.work615; import java.util.ArrayList;import java.util.Date;import java.util.List; public
JAVA復習5 Java循環結構 - for, while 及 do...while
con dsm key width 限定 一個 bre ava mil 就我所知道的編程語言中都有循環語句: for, while 及 do...while,在這裏要說的就是他們的差別,我不喜歡用語言來說,大家看代碼:coding.............
python基礎5 if-else流程判斷,for循環和while循環
代碼 整數和 data valid 語法錯誤 usr 定義 small 提示 本節主要內容: if-else流程判斷 for循環 while循環 參考網頁 if-else流程判斷 if 語句概述 計算機之所以能做很多自動化的任務,因為它可以自己做條件判斷。 比如,輸入用
CentOS 6.5 安裝 rlwrap軟件for sqlplus
rlwrapCentOS 6.5 安裝 rlwrap軟件for sqlplus目的:解決sqlplus連接oracle的方便使用(如左右鍵,上下鍵的靈活使用)提示:依yum方式安裝,需要連接第三方的yum源,因為centos默認的yum源中沒有rlwarap組件步驟1.root用戶登入OS 2.#rpm -i
php <5.5 curl post and file 請求
cep 文件上傳 output errno accep dir 適配 add loaded /** * 跨域post請求(適配文件上傳) * @param $url 上傳地址 * @param $post_data 請求數據 */