In newer versions (post 1.13) of Go, you don’t need to set environment variables like GOPATH
, GOBIN
, etc.
You also need to have a go.mod
file at the project root. This will make the directory a Go module. This is also where the .git/
is located. This means that only one go.mod
is needed per repository. Inside the project root you could do a go mod init remote-repo.com/username/repository
I installed Go using Homebrew on macOS so GOROOT
is /opt/homebrew/Cellar/go/1.17.5/libexec
. This location contains the standard library and runtimes for Go.
test
and run
commands are run in the format go COMMAND package_path/xxx
. Without specifying the package_path ./
and just running go COMMAND xxx
, the compiler assumes that the module xxx is located in GOROOT, and throws error package xxx is not in GOROOT (path/to/GOROOT/src/xxx)
because it doesn’t exist.
This behavior is expected because the package we are working with is not part of the Go SDK, i.e., not in GOROOT
. The package we are working with will either end up in the go workspace or in the current working directory. Running go install
compiles and puts an executable binary in $GOBIN
(a.k.a $GOPATH/bin
– here $GOPATH
is the Go workspace). Running go build
from inside a package compiles and puts an execuatble in that directory.
You haven’t listed the files inside the server/
package and which file has the main function, so I’ll emulate 3 workflows of a calculator each demonstrating more complexity. The last workflow is similar to your directory structure.
Directory Structure
Version 1:
-
Getting started with packages
-
Basic functionality
calculatorv1
├── go.mod <- go mod init github.com/yourname/calculatorv1
└── basic/
├── add.go
├── add_test.go
├── main.go
├── multiply.go
└── multiply_test.go
Version 2:
-
More functionality
-
Multiple packages
calculatorv2
├── go.mod <- go mod init github.com/yourname/calculatorv2
├── main.go
└── basic/
│ ├── add.go
│ ├── add_test.go
│ ├── multiply.go
│ └── multiply_test.go
└─── advanced/
├── square.go
└── square_test.go
Version 3:
-
Even more functionality
-
Nested packages
calculatorv3
├── go.mod <- go mod init github.com/yourname/calculatorv3
├── main.go
└── basic/
│ ├── add.go
│ ├── add_test.go
│ ├── multiply.go
│ └── multiply_test.go
└─── advanced/
├── square.go
├── square_test.go
└── scientific/
├── declog.go
└── declog_test.go
Workflow
Note: Substitute xxx
with basic
, advanced
, or advanced/scientific
depending on the version you’re working with.
-
Initialize Go module in the project directory (one of
calculatorv1
,calculatorv2
, orcalculatorv3
) usinggo mod init
-
Run tests
go test -v ./...
(from the project root, recursively execute all test suites)OR
go test -v ./xxx
(from the project root, run the test suite in package “xxx”)OR
cd xxx/ go test -v # (from inside the package)
-
Compile and execute package
go run ./...
(from the project root, recursively run all.go
files except tests)OR
go run ./xxx
(from the project root, run all.go
files in “xxx” package except tests)OR
cd xxx go run . # (from inside the package)
NOTE: Only files in the main package are executable, i.e., files having declaration
package main
. This means thatgo run ./xxx
will only work with version1, and not versions 2 and 3. So instead for versions 2 and 3, rungo run main.go
Code
Very easy to fill in incomplete bits
Version 1
add.go
package main
func addition(x int, y int) int {
return x + y
}
add_test.go
package main
import "testing"
func TestAdd(t *testing.T) {
t.Run("adding two positive numbers", func(t *testing.T) {
sum := addition(2, 2)
expected := 4
if sum != expected {
t.Errorf("Expected %d; but got %d", expected, sum)
}
})
t.Run("adding two negative numbers", func(t *testing.T) {
sum := addition(-3, -4)
expected := -7
if sum != expected {
t.Errorf("Expected %d; but got %d", expected, sum)
}
})
t.Run("adding one positive and one negative integer", func(t *testing.T) {
sum := addition(1, -3)
expected := -2
if sum != expected {
t.Errorf("Expected %d; but got %d", expected, sum)
}
})
}
main.go
package main
import "fmt"
func main() {
var num1 int = 1
var num2 int = 2
sum := addition(num1, num2)
product := multiplication(num1, num2)
fmt.Printf("The sum of %d and %d is %d\n", num1, num2, sum)
fmt.Printf("The multiplication of %d and %d is %d\n", num1, num2, product)
}
Version 2
main.go
package main
import (
"fmt"
"github.com/yourname/calculatorv2/basic"
"github.com/yourname/calculatorv2/advanced"
)
func main() {
var num1 int = 1
var num2 int = 2
product := basic.Multiplication(num1, num2)
square := advanced.Square(num2)
fmt.Printf("The product of %d and %d is %d\n", num1, num2, product)
fmt.Printf("The square of %d is %d\n", num2, square)
}
multiply.go
package basic
func Multiplication(x int, y int) int {
return x * y
}
multiply_test.go
package basic
import "testing"
func TestMultiply(t *testing.T) {
t.Run("multiplying two positive numbers", func(t *testing.T) {
sum := Multiplication(2, 2)
expected := 4
if sum != expected {
t.Errorf("Expected %d; but got %d", expected, sum)
}
})
t.Run("multiplying two negative numbers", func(t *testing.T) {
sum := Multiplication(-3, -4)
expected := 12
if sum != expected {
t.Errorf("Expected %d; but got %d", expected, sum)
}
})
t.Run("multiplying one positive and one negative integer", func(t *testing.T) {
sum := Multiplication(1, -3)
expected := -3
if sum != expected {
t.Errorf("Expected %d; but got %d", expected, sum)
}
})
}
square.go
package advanced
func Square(x int) int {
return x * x
}
Version 3
main.go
package main
import (
"fmt"
"github.com/yourname/calculatorv3/basic"
"github.com/yourname/calculatorv3/advanced"
"github.com/yourname/calculatorv3/advanced/scientific"
)
func main() {
var num1 int = 1
var num2 int = 2
var num3 float64 = 2
product := basic.Multiplication(num1, num2)
square := advanced.Square(num2)
decimallog := scientific.DecimalLog(num3)
fmt.Printf("The product of %d and %d is %d\n", num1, num2, product)
fmt.Printf("The square of %d is %d\n", num2, square)
fmt.Printf("The decimal log (base 10) of %f is %f\n", num3, decimallog)
}
square.go
package advanced
func Square(x int) int {
return x * x
}
declog.go
package scientific
import "math"
func DecimalLog(x float64) float64 {
return math.Log10(x)
}
declog_test.go
package scientific
import "testing"
func TestDecimalLog(t *testing.T) {
t.Run("adding two positive numbers", func(t *testing.T) {
sum := DecimalLog(100)
expected := 2.0
if sum != expected {
t.Errorf("Expected %f; but got %f", expected, sum)
}
})
t.Run("adding two negative numbers", func(t *testing.T) {
sum := DecimalLog(10)
expected := 1.0
if sum != expected {
t.Errorf("Expected %f; but got %f", expected, sum)
}
})
}