計算機科学のブログ

多国通貨(The Money Example) 疑念をテストに翻訳する(Apples and Oranges) 異なる通貨間での比較

テスト駆動開発 (Kent Beck(著)、和田 卓人(翻訳)、オーム社)の第Ⅰ部(多国通貨(The Money Example))、第7章(疑念をテストに翻訳する(Apples and Oranges))をJavaではなくGo言語で取り組んでみる。

コード

money_test.go

package money

import "testing"

func TestDollarTimes(t *testing.T) {
	five := NewDollar(5)
	tests := []struct {
		m    int
		want Dollar
	}{
		{2, NewDollar(10)},
		{3, NewDollar(15)},
	}
	for _, test := range tests {
		got := five.Times(test.m)
		want := test.want
		if !got.Eq(want) {
			t.Errorf("%v.Times(%v) got %v, want %v", five, test.m, got, want)
		}
	}
}
func TestDollarEq(t *testing.T) {
	five := NewDollar(5)
	tests := []struct {
		d    Eqer
		want bool
	}{
		{NewDollar(5), true},
		{NewDollar(6), false},
	}
	for _, test := range tests {
		got := five.Eq(test.d)
		if got != test.want {
			t.Errorf("%v.Eq(%v) got %v, want %v",
				five, test.d, got, test.want)
		}
	}
}

func TestFrancTimes(t *testing.T) {
	five := NewFranc(5)
	tests := []struct {
		m    int
		want Franc
	}{
		{2, NewFranc(10)},
		{3, NewFranc(15)},
	}
	for _, test := range tests {
		got := five.Times(test.m)
		want := test.want
		if !got.Eq(want) {
			t.Errorf("%v.Eq(%v) got %v, want %v",
				five, test.m, got, want)
		}
	}
}
func TestFrancEq(t *testing.T) {
	five := NewFranc(5)
	tests := []struct {
		d    Eqer
		want bool
	}{
		{NewFranc(5), true},
		{NewFranc(6), false},
		{NewDollar(5), false},
	}
	for _, test := range tests {
		got := five.Eq(test.d)
		if got != test.want {
			t.Errorf("%v.Eq(%v) got %v, want %v",
				five, test.d, got, test.want)
		}
	}
}

money.go

package money

// Money ...
type Money struct {
	amount int
}

// Eqer ...
type Eqer interface {
	Eq(Eqer) bool
}

// Dollar ...
type Dollar struct {
	Money
}

// NewDollar ...
func NewDollar(amount int) Dollar {
	// return Dollar{amount:amount}
	return Dollar{Money{amount: amount}}
}

// Times ...
func (d Dollar) Times(m int) Dollar {
	return NewDollar(d.amount * m)
}

// Eq ...
func (d Dollar) Eq(y Eqer) bool {
	dy, ok := y.(Dollar)
	if ok {
		return d.amount == dy.amount
	}
	return false
}

// Franc ...
type Franc struct {
	Money
}

// NewFranc ...
func NewFranc(amount int) Franc {
	return Franc{Money{amount: amount}}
}

// Times ...
func (f Franc) Times(m int) Franc {
	return NewFranc(f.amount * m)
}

// Eq ...
func (f Franc) Eq(y Eqer) bool {
	fy, ok := y.(Franc)
	if ok {
		return f.amount == fy.amount
	}
	return false
}

入出力結果(Terminal, Zsh)

% go test
--- FAIL: TestMoneyEq (0.00s)
    money_test.go:63: {{5}}.Eq({{5}}) got true, want false
FAIL
exit status 1
FAIL	money	0.407s
% go test
--- FAIL: TestMoneyEq (0.00s)
    money_test.go:33: {{5}}.Eq({{5}}) got false, want true
    money_test.go:63: {{5}}.Eq({{5}}) got true, want false
FAIL
exit status 1
FAIL	money	0.309s
% go test
--- FAIL: TestMoneyEq (0.00s)
    money_test.go:48: {{10}}.Eq({{10}}) got false, want true
    money_test.go:48: {{15}}.Eq({{15}}) got false, want true
    money_test.go:63: {{5}}.Eq({{5}}) got true, want false
FAIL
exit status 1
FAIL	money	0.282s
% go test
# money [money.test]
./money_test.go:46:28: cannot use test.fy.Money (type Money) as type Eqer in argument to test.fx.Eq:
	Money does not implement Eqer (missing Eq method)
./money_test.go:60:22: test.f.Money.Eq undefined (type Money has no field or method Eq)
FAIL	money [build failed]
% go test
PASS
ok  	money	0.689s
% go test
PASS
ok  	money	0.290s
% go test
--- FAIL: TestDollarTimes (0.00s)
    money_test.go:18: {{5}}.Times(2) got {{10}}, want {{10}}
    money_test.go:18: {{5}}.Times(3) got {{15}}, want {{15}}
FAIL
exit status 1
FAIL	money	0.293s
% go test
PASS
ok  	money	0.223s
% go test
--- FAIL: TestFrancEq (0.00s)
    money_test.go:71: {{5}}.Eq({{5}}) got true, want false
FAIL
exit status 1
FAIL	money	0.275s
% go test
PASS
ok  	money	0.223s
%