Adding structs and interfaces
parent
eeef9622df
commit
3686956a02
@ -0,0 +1,7 @@
|
|||||||
|
# Testing Structs
|
||||||
|
|
||||||
|
You can run individual tests like:
|
||||||
|
|
||||||
|
```
|
||||||
|
go test -run TestArea/Rectangle
|
||||||
|
```
|
@ -0,0 +1,3 @@
|
|||||||
|
module structs
|
||||||
|
|
||||||
|
go 1.21.0
|
@ -0,0 +1,49 @@
|
|||||||
|
package structs
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
// In Go interface resolution is implicit. So Rectangle and Cirle have
|
||||||
|
// receiver functions that satisfy the Shape interface.
|
||||||
|
type Shape interface {
|
||||||
|
Area() float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Rectangle struct {
|
||||||
|
Width float64
|
||||||
|
Height float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Circle struct {
|
||||||
|
Radius float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Triangle struct {
|
||||||
|
Base float64
|
||||||
|
Height float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are examples of functions (not methods)
|
||||||
|
// Perimeter calculates the perimeter of a rectangle
|
||||||
|
func Perimeter(rectangle Rectangle) float64 {
|
||||||
|
return 2 * (rectangle.Width + rectangle.Height)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Area calculates the area of a rectangle
|
||||||
|
func Area(rectangle Rectangle) float64 {
|
||||||
|
return rectangle.Width * rectangle.Height
|
||||||
|
}
|
||||||
|
|
||||||
|
// A method is a function with a receiver. A method declaration binds an identifier,
|
||||||
|
// the method name, to a method, and associates the method with the receiver's base type.
|
||||||
|
func (r Rectangle) Area() float64 {
|
||||||
|
return r.Height * r.Width
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Circle) Area() float64 {
|
||||||
|
return math.Pow(c.Radius, 2) * math.Pi
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Triangle) Area() float64 {
|
||||||
|
// return (t.Base * t.Height) / 2
|
||||||
|
return (t.Base * t.Height) * 0.5
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
package structs
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestPerimeter(t *testing.T) {
|
||||||
|
rectangle := Rectangle{10.0, 10.0}
|
||||||
|
got := Perimeter(rectangle)
|
||||||
|
want := 40.0
|
||||||
|
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("got %.2f want %.2f", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// %.2f is replaced with %g which will print a more precise decimal number in an error message.
|
||||||
|
|
||||||
|
func TestArea(t *testing.T) {
|
||||||
|
|
||||||
|
// Helper function
|
||||||
|
checkArea := func(t testing.TB, shape Shape, want float64) {
|
||||||
|
t.Helper()
|
||||||
|
got := shape.Area()
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("got %g want %g", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("area rectangle", func(t *testing.T) {
|
||||||
|
rectangle := Rectangle{12.0, 6.0}
|
||||||
|
checkArea(t, rectangle, 72.0)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("area circle", func(t *testing.T) {
|
||||||
|
circle := Circle{10}
|
||||||
|
checkArea(t, circle, 314.1592653589793)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://go.dev/wiki/TableDrivenTests are useful when you want to build a list of test cases that can be tested in the same manner.
|
||||||
|
// They are a great fit when you wish to test various implementations of an interface, or if the data being passed in to a function has lots of different requirements that need testing.
|
||||||
|
func TestAreaTable(t *testing.T) {
|
||||||
|
|
||||||
|
// "anonymous struct"
|
||||||
|
areaTests := []struct {
|
||||||
|
name string
|
||||||
|
shape Shape
|
||||||
|
want float64
|
||||||
|
}{
|
||||||
|
// example showing named arguments. Arguably it is more readable.
|
||||||
|
{name: "Rectangle", shape: Rectangle{Width: 12, Height: 6}, want: 72.0},
|
||||||
|
{"Circle", Circle{10}, 314.1592653589793},
|
||||||
|
{"Triangle", Triangle{12, 6}, 36.0},
|
||||||
|
}
|
||||||
|
|
||||||
|
// for _, tt := range areaTests {
|
||||||
|
// got := tt.shape.Area()
|
||||||
|
// if got != tt.want {
|
||||||
|
// // %#v format string will print out our struct with the values in its field
|
||||||
|
// t.Errorf("%#v got %g want %g", tt, got, tt.want)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Wrap in t.Run for better debug output and test failure identification
|
||||||
|
for _, tt := range areaTests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := tt.shape.Area()
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("%#v got %g want %g", tt, got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue