計算機科学のブログ

多国通貨(The Money Example) 設計とメタファー(Addition, Finally) interface

テスト駆動開発 (Kent Beck(著)、和田 卓人(翻訳)、オーム社)の第Ⅰ部(多国通貨(The Money Example))、第12章(設計とメタファー(Addition, Finally))をJavaではなくGo言語で取り組んでみる。

コード

money_test.go

package money

import "testing"

func TestTimes(t *testing.T) {
	five := NewMoneyDollar(5)
	tests := []struct {
		m int
		d Money
	}{
		{2, NewMoneyDollar(10)},
		{3, NewMoneyDollar(15)},
	}
	for _, test := range tests {
		got := five.Times(test.m)
		want := test.d
		if got != want {
			t.Errorf("%v.Times(%v) got %v, want %v", five, test.m, got, want)
		}
	}
}
func TestCurrency(t *testing.T) {
	tests := []struct {
		c string
		m Money
	}{
		{"USD", NewMoneyDollar(1)},
		{"CHF", NewMoneyFranc(1)},
	}
	for _, test := range tests {
		got := test.m.Currency()
		want := test.c
		if got != want {
			t.Errorf("%v.Currency() got %v, want %v",
				test.m, got, want)
		}
	}
}
func TestEq(t *testing.T) {
	tests := []struct {
		mx, my Money
		want   bool
	}{
		{NewMoneyDollar(5), NewMoneyDollar(5), true},
		{NewMoneyDollar(5), NewMoneyDollar(6), false},
		{NewMoneyFranc(5), NewMoneyDollar(5), false},
	}
	for _, test := range tests {
		got := test.mx.Eq(test.my)
		want := test.want
		if got != want {
			t.Errorf("%v.Eq(%v) got %v, want %v",
				test.mx, test.my, got, want)
		}
	}
}

func TestAdd(t *testing.T) {
	// tests := []struct {
	// 	mx, my, want Money
	// }{
	// 	{NewMoneyDollar(5), NewMoneyDollar(5), NewMoneyDollar(10)},
	// }
	// for _, test := range tests {
	// 	got := test.mx.Add(test.my)
	// 	if got.Ne(reduced) {
	// 		t.Errorf("%v.Add(%v) got %v, want %v",
	// 			test.mx, my, got, test.want)
	// 	}
	// }
	five := NewMoneyDollar(5)
	sum := five.Add(five)
	bank := NewBank()
	got := bank.reduce(sum, "USD")
	want := NewMoneyDollar(10)
	if got.Ne(want) {
		t.Errorf("%v.Add(%v) got %v, want  %v", five, five, got, want)
	}
}

money.go

package money

import "fmt"

// Expression ...
type Expression interface{}

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

func (mx Money) String() string {
	return fmt.Sprintf("%v %v", mx.amount, mx.currency)
}

// NewMoney ...
func NewMoney(amount int, currency string) Money {
	return Money{amount, currency}
}

// Currency ...
func (mx Money) Currency() string {
	return mx.currency
}

// Eq ...
func (mx Money) Eq(my Money) bool {
	return mx.amount == my.amount && mx.currency == my.currency
}

// Ne ...
func (mx Money) Ne(my Money) bool {
	return !mx.Eq(my)
}

// Times ...
func (mx Money) Times(m int) Money {
	return NewMoney(mx.amount*m, mx.currency)
}

// NewMoneyDollar ...
func NewMoneyDollar(amount int) Money {
	return NewMoney(amount, "USD")
}

// NewMoneyFranc ...
func NewMoneyFranc(amount int) Money {
	return NewMoney(amount, "CHF")
}

// Add ...
// func (mx Money) Add(my Money) Money {
// 	return NewMoney(mx.amount+my.amount, mx.currency)
// }
func (mx Money) Add(my Money) Expression {
	return NewMoney(mx.amount+my.amount, mx.currency)
}

// Bank 通貨を換算する
type Bank struct{}

// NewBank ...
func NewBank() Bank {
	return Bank{}
}
func (b Bank) reduce(source Expression, to string) Money {
	return NewMoneyDollar(10)
}

入出力結果(Terminal, Zsh)

% go test
PASS
ok  	money	0.368s
% go test
--- FAIL: TestAdd (0.00s)
    money_test.go:77: 5 USD.Add(5 USD) got 0 , want 10 USD
FAIL
exit status 1
FAIL	money	0.284s
%  go test
PASS
ok  	money	0.225s
%