Go testing
Different test cases
Unit testing
Functional testing
E2E testing
Fuzzing
Unit testing
Unit testing is a software development process in which the smallest testable parts of an application, called units, are individually and independently scrutinized for proper operation
Unit testing
go test -v ./...
Unit testing
=== RUN TestMyPassed
--- PASS: TestMyPassed (0.00s)
=== RUN TestMyFailed
--- FAIL: TestMyFailed (0.00s)
Unit testing
package demo
var the_var = "the_value"
func awesome() (s string) {
if the_var == "the_value" {
s = "working"
}
if len(the_var) == 0 {
s = "empty"
}
if the_var == "bypass" {
s = "bypass"
}
if called(the_var) {
s = "called"
}
return
}
Unit testing
func Test_awesome(t *testing.T) {
if awesome() != "working" {
t.Errorf("The awesome function must return `working` while passed initial value, %s given", awesome())
}
the_var = ""
if awesome() != "empty" {
t.Errorf("The awesome function must return an empty string while passed empty value, %s given", awesome())
}
the_var = "bypass"
if awesome() != "bypass" {
t.Errorf("The awesome function must return `bypass` string while passed `bypass` value, %s given", awesome())
}
the_var = "another_valid"
if awesome() != "called" {
t.Errorf("The awesome function must return `called` string while passed `another_valid` value, %s given", awesome())
}
}
Unit testing
func Test_awesome_working(t *testing.T) {
if awesome() != "working" {
t.Errorf("The awesome function must return `working` while passed initial value, %s given", awesome())
}
}
func Test_awesome_empty(t *testing.T) {
the_var = ""
if awesome() != "empty" {
t.Errorf("The awesome function must return an empty string while passed empty value, %s given", awesome())
}
}
func Test_awesome_bypass(t *testing.T) {
the_var = "bypass"
if awesome() != "bypass" {
t.Errorf("The awesome function must return `bypass` string while passed `bypass` value, %s given", awesome())
}
}
func Test_awesome_called(t *testing.T) {
the_var = "another_valid"
if awesome() != "called" {
t.Errorf("The awesome function must return `called` string while passed `another_valid` value, %s given", awesome())
}
}
Unit testing
ok my_package 0.155s coverage: 92.9% of statements
my_package/main.go:5: called 80.0%
my_package/main.go:17: awesome 100.0%
total: (statements) 92.9%
go test ./... -coverprofile cover.out && \
go tool cover -func cover.out
Unit testing
func Test_called_valid(t *testing.T) {
if !called("valid") {
t.Errorf("The called function must return `true` while passed a valid value, %v given", called("valid"))
}
}
ok my_package 0.180s coverage: 100.0% of statements
my_package/main.go:5: called 100.0%
my_package/main.go:17: awesome 100.0%
total: (statements) 100.0%
Unit testing
Les race conditions
A race condition occurs when multiple threads try to access and modify the same data (memory address).
Unit testing
var sharedInt int = 0
var unusedValue int = 0
func runSimpleReader() {
for {
var val int = sharedInt
if val%10 == 0 {
unusedValue = unusedValue + 1
}
}
}
func runSimpleWriter() {
for {
sharedInt = sharedInt + 1
}
}
func startSimpleReadWrite() {
go runSimpleReader()
go runSimpleWriter()
time.Sleep(10 * time.Second)
}
Unit testing
go run -race .
==================
WARNING: DATA RACE
Fuzzing
In programming and software development, fuzzing or fuzz testing is an automated software testing technique that involves providing invalid, unexpected, or random data as inputs to a computer program
Fuzzing
Fuzzing
Introduced in Go 1.18
Differ from classic testing.T
Implement fuzzing interface testing.F
Fuzzing
go test -v -fuzztime=2s ./...
Fuzzing
package demo
import "testing"
func FuzzThis(f *testing.F) {
f.Fuzz(func(t *testing.T, a string) {
if value(a) {
t.Error("The value is equal to `this is my value`.")
}
})
}
package demo
import "testing"
func value(v string) bool {
return v == "this is my value"
}
Fuzzing
=== RUN FuzzThis
=== RUN FuzzThis/04358d4af4e8ef32223beec89298ad6721bfc244a75b77a139bd898d3bb3cbcc
=== RUN FuzzThis/28e3bb38264eccee98122f81aa5be66182144a75e42aa783fcf10509c2127083
=== RUN FuzzThis/43b9989630564313daa99fbd4cbb4ee155f698e3332d7af823ab87b5a1897618
--- PASS: FuzzThis (0.00s)
--- PASS: FuzzThis/04358d4af4e8ef32223beec89298ad6721bfc244a75b77a139bd898d3bb3cbcc (0.00s)
--- PASS: FuzzThis/28e3bb38264eccee98122f81aa5be66182144a75e42aa783fcf10509c2127083 (0.00s)
--- PASS: FuzzThis/43b9989630564313daa99fbd4cbb4ee155f698e3332d7af823ab87b5a1897618 (0.00s)
PASS
ok something 0.156s
Fuzzing
package demo
import "testing"
func FuzzThis(f *testing.F) {
f.Add("this is my ")
f.Fuzz(func(t *testing.T, a string) {
if value(a) {
t.Error("The value is equal to `this is my value`.")
}
})
}
package demo
import "testing"
func value(v string) bool {
return v == "this is my value"
}
Fuzzing
=== RUN FuzzThis
=== RUN FuzzThis/seed#0
base_test.go:12: The value is equal to `this is my value`.
=== RUN FuzzThis/04358d4af4e8ef32223beec89298ad6721bfc244a75b77a139bd898d3bb3cbcc
=== RUN FuzzThis/28e3bb38264eccee98122f81aa5be66182144a75e42aa783fcf10509c2127083
=== RUN FuzzThis/43b9989630564313daa99fbd4cbb4ee155f698e3332d7af823ab87b5a1897618
--- FAIL: FuzzThis (0.00s)
--- FAIL: FuzzThis/seed#0 (0.00s)
--- PASS: FuzzThis/04358d4af4e8ef32223beec89298ad6721bfc244a75b77a139bd898d3bb3cbcc (0.00s)
--- PASS: FuzzThis/28e3bb38264eccee98122f81aa5be66182144a75e42aa783fcf10509c2127083 (0.00s)
--- PASS: FuzzThis/43b9989630564313daa99fbd4cbb4ee155f698e3332d7af823ab87b5a1897618 (0.00s)
FAIL
FAIL something 0.206s
FAIL
Fuzzing
More complex fuzzing
https://github.com/google/gofuzz
https://github.com/dvyukov/go-fuzz
Functional testing
Test your feature according to the specifications
Functional testing
I developed an API
I want to test the behavior
I will write a service mock
I send an HTTP request to my API
Wait and see...
Functional testing
req := httptest.NewRequest(http.MethodGet, "/handled", nil)
app.ServeHTTP(res, req)
database := mockDatabase()
database.get("Something", "VALUE")
Functional testing
{
debug
}
:4443
route /mock-my-external-route-empty-body {
header Content-Type application/json
respond "{}"
}
route /mock-my-external-route-filled-body {
header Content-Type application/json
respond "{\"is_filled\": true}"
}
Functional testing
Mock the external services
Reduce dependencies
Ensure the app resilience
E2E tests
test the functionality and performance of an application under product-like circumstances and data to replicate live settings
E2E tests
Postman / Insomnia
Cypress / Selenium
Postman
Postman
npm install -g newman
newman run my-collection.json
Postman
version: v1.0
name: cds_goes_bruh
jobs:
- job: Run newman/E2E tests
steps:
#...
- script:
- '#!/bin/bash'
- npm install -g newman
- newman run my-collection.json
requirements:
- binary: npm
Did I hear CDS?
I don't know if it's really working
Secure your builds
On the laptop
pre-commit/pre-push
On the CI
unit + fuzz (at least)
on push
unit + fuzz + functional
on merge / deploy / tag
all
Thank you & questions
Les tests en go
By darkweak
Les tests en go
- 327