GRACE was using the gometalinter
to enforce community recommended style guidelines on Go code. However, the gometalinter
project has been deprecated in favor of golangci-lint
and GRACE will be migrating to this linter instead.
- Favor using table driven tests (See Figure 1).
- Keep tests focused. Each test case should test a single behavior and be named accordingly.
- Use assertions instead of if statements, where possible (See Figure 2).
- Use sub-tests to differentiate error messages when using assertions. This will make debugging easier.
- Test cases should cover both the Happy path and the Unhappy path (See Happy Path vs Unhappy Path).
- Use native go interfaces when feasible (See Figure 3).
- Use GoMock when go interfaces alone are not sufficient (See Figure 4).
Well written code will generally have line, branch and mutation coverage higher than 80%. Prioritize testing code that is most likely to change in the future.
// Sum ... returns the sum of two numbers
func Sum(a, b int) int {
return a + b
}
func TestSum(t *testing.T) {
tt := map[string]struct {
A int
B int
Expected int
}{
"1+2=3": {1, 2, 3},
"2+2=4": {2, 2, 4},
}
for name, tc := range tt {
tc := tc
t.Run(name, func(t *testing.T) {
actual := Sum(tc.A, tc.B)
assert.Equal(t, tc.Expected, actual)
})
}
}
// Read ... reads the file at 'path' and returns the contents as a string
func Read(path string) (string, error) {
byt, err := ioutil.ReadFile(path)
if err != nil {
return "", err
}
return string(byt), nil
}
func TestRead(t *testing.T) {
tt := map[string]struct {
Path string
Expected string
Error bool
}{
"File": {Path: "localfile.json", Expected: `{"data":"this"}`},
"FileErr": {Path: "non_existent", Error: true},
}
for name, tc := range tt {
tc := tc
t.Run(name, func(t *testing.T) {
actual, err := Read(tc.Path)
if !tc.Error { // Assert not used for readability
assert.Nil(t, err)
}
assert.Equal(t, tc.Expected, actual)
})
}
}
package dog
...
type Dog struct {
}
func New() *Dog {
return &Dog{}
}
func (d *Dog) Bark() string {
return "bark!"
}
type IDog interface {
Bark() string
}
var _ IDog = (*Dog)(nil)
package main
...
func main() {
d := dog.New()
PrintMsg(d)
}
func GetSound(t dog.IDog) string {
return t.Bark()
}
package main
...
type MockDog struct {
dog.IDog
bark string
}
func (m *MockDog) Bark() string {
return m.bark
}
func TestGetSound(t *testing.T) {
expected := "yip!"
md := &MockDog{bark: expected}
actual := GetSound(md)
assert.Equal(t, expected, actual)
}
// Code generated by MockGen. DO NOT EDIT.
// Source: ..\dog.go
// Package mock_dog is a generated GoMock package.
package mock_dog
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockIDog is a mock of IDog interface
type MockIDog struct {
ctrl *gomock.Controller
recorder *MockIDogMockRecorder
}
// MockIDogMockRecorder is the mock recorder for MockIDog
type MockIDogMockRecorder struct {
mock *MockIDog
}
// NewMockIDog creates a new mock instance
func NewMockIDog(ctrl *gomock.Controller) *MockIDog {
mock := &MockIDog{ctrl: ctrl}
mock.recorder = &MockIDogMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockIDog) EXPECT() *MockIDogMockRecorder {
return m.recorder
}
// Bark mocks base method
func (m *MockIDog) Bark() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Bark")
ret0, _ := ret[0].(string)
return ret0
}
// Bark indicates an expected call of Bark
func (mr *MockIDogMockRecorder) Bark() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bark", reflect.TypeOf((*MockIDog)(nil).Bark))
}
package main
...
func TestSound(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
expected := "yip!"
m := mock_dog.NewMockIDog(ctrl)
m.EXPECT().Bark().Times(1).Return(expected)
actual := sound(m)
assert.Equal(t, expected, actual)
}
The GRACE development team will use the Terraform Best Practices GitBook by Anton Babenko as a style guide for GRACE Terraform code. The team will document additional clarification, modifications, deviations and addendums to the guide in this repository.
[top]
- Terraform Best Practices
- Hashicorp Terraform Style Conventions
- Hashicorp Terraform Recommended Practices
- Hashicorp Terraform Getting Started - AWS Dependencies
- GRACE IAM Naming Standard-Draft
- Jon Brouse Terraform Style Guide
- ASICS Digital Group Terraform Style Guide
- How to use Terraform as a team – Gruntwork - Gruntwork Blog
- Introducing Terraform at GumGum
- Template/Module iteration terraform style - Google Groups
- Pete's Terraform Tips – Pete Shima – Medium
[top]
There is a draft GRACE IAM Naming Standard in Google Docs.
This project is in the worldwide public domain. As stated in CONTRIBUTING:
This project is in the public domain within the United States, and copyright and related rights in the work worldwide are waived through the CC0 1.0 Universal public domain dedication.
All contributions to this project will be released under the CC0 dedication. By submitting a pull request, you are agreeing to comply with this waiver of copyright interest.
[top]