撰寫銀行核心套件
現在我們已經讓基礎專案與測試檔案一起執行,接下來讓我們開始撰寫程式碼,實作前一個單元的功能和需求。 我們在這裡回顧了稍早討論的幾個主題,例如錯誤、結構和方法。
開啟 $GOPATH/src/bankcore/bank.go
檔案,接著移除 Hello()
函式,然後開始撰寫我們的線上銀行系統核心邏輯。
建立客戶和帳戶的結構
首先要建立一個 Customer
結構,收集想成為銀行客戶人士的姓名、地址和電話號碼。 此外,我們還需要 Account
資料的結構。 因為一名客戶可以有多個帳戶,所以我們會將客戶資訊內嵌到帳戶物件中。 其實就是要建立在 TestAccount
測試中定義的內容。
我們需要的結構可能像以下程式碼範例:
package bank
// Customer ...
type Customer struct {
Name string
Address string
Phone string
}
// Account ...
type Account struct {
Customer
Number int32
Balance float64
}
現在,當您在終端機中執行 go test -v
命令時,您應該會看到測試已通過:
=== RUN TestAccount
--- PASS: TestAccount (0.00s)
PASS
ok github.com/msft/bank 0.094s
這項測試之所以會通過,是因為我們實作了 Customer
和 Account
的結構。 有了結構後,讓我們撰寫方法,在銀行初始版本中新增所需的功能。 這些功能包括存款、提款和轉帳。
實作存款方法
我們需要從一個允許在帳戶中增加金額的方法開始。 但在這麼做之前,要先在 bank_test.go
檔案中建立 TestDeposit
函式:
func TestDeposit(t *testing.T) {
account := Account{
Customer: Customer{
Name: "John",
Address: "Los Angeles, California",
Phone: "(213) 555 0147",
},
Number: 1001,
Balance: 0,
}
account.Deposit(10)
if account.Balance != 10 {
t.Error("balance is not being updated after a deposit")
}
}
當您執行 go test -v
時,您應該會在輸出中看到失敗的測試:
# github.com/msft/bank [github.com/msft/bank.test]
./bank_test.go:32:9: account.Deposit undefined (type Account has no field or method Deposit)
FAIL github.com/msft/bank [build failed]
為滿足前一項測試,讓我們建立 Account
結構的 Deposit
方法:如果收到的金額等於或小於零,則會傳回錯誤; 否則,只要將收到的金額加入帳戶餘額即可。
請為 Deposit
方法使用下列程式碼:
// Deposit ...
func (a *Account) Deposit(amount float64) error {
if amount <= 0 {
return errors.New("the amount to deposit should be greater than zero")
}
a.Balance += amount
return nil
}
當您執行 go test -v
時,應該會看到測試已通過:
=== RUN TestAccount
--- PASS: TestAccount (0.00s)
=== RUN TestDeposit
--- PASS: TestDeposit (0.00s)
PASS
ok github.com/msft/bank 0.193s
您也可以撰寫測試,確認嘗試存入負數金額時會收到錯誤,如下所示:
func TestDepositInvalid(t *testing.T) {
account := Account{
Customer: Customer{
Name: "John",
Address: "Los Angeles, California",
Phone: "(213) 555 0147",
},
Number: 1001,
Balance: 0,
}
if err := account.Deposit(-10); err == nil {
t.Error("only positive numbers should be allowed to deposit")
}
}
當您執行 go test -v
命令時,應該會看到測試已通過:
=== RUN TestAccount
--- PASS: TestAccount (0.00s)
=== RUN TestDeposit
--- PASS: TestDeposit (0.00s)
=== RUN TestDepositInvalid
--- PASS: TestDepositInvalid (0.00s)
PASS
ok github.com/msft/bank 0.197s
注意
從這裡開始,我們會為每個方法撰寫一個測試案例。 但是您應該為程式撰寫盡可能多的測試,以便應對各種預期和非預期的情況。 例如,此案例會測試錯誤處理邏輯。
實作提款方法
撰寫 Withdraw
功能之前,要先撰寫其測試:
func TestWithdraw(t *testing.T) {
account := Account{
Customer: Customer{
Name: "John",
Address: "Los Angeles, California",
Phone: "(213) 555 0147",
},
Number: 1001,
Balance: 0,
}
account.Deposit(10)
account.Withdraw(10)
if account.Balance != 0 {
t.Error("balance is not being updated after withdraw")
}
}
當您執行 go test -v
命令時,您應該會在輸出中看到失敗的測試:
# github.com/msft/bank [github.com/msft/bank.test]
./bank_test.go:67:9: account.Withdraw undefined (type Account has no field or method Withdraw)
FAIL github.com/msft/bank [build failed]
讓我們實作 Withdraw
方法的邏輯,收到的參數金額即為帳戶餘額減少的金額。 與前面的流程一樣,我們必須驗證收到的數字是否大於零,以及帳戶餘額是否足夠。
請為 Withdraw
方法使用下列程式碼:
// Withdraw ...
func (a *Account) Withdraw(amount float64) error {
if amount <= 0 {
return errors.New("the amount to withdraw should be greater than zero")
}
if a.Balance < amount {
return errors.New("the amount to withdraw should be less than the account's balance")
}
a.Balance -= amount
return nil
}
當您執行 go test -v
命令時,應該會看到測試已通過:
=== RUN TestAccount
--- PASS: TestAccount (0.00s)
=== RUN TestDeposit
--- PASS: TestDeposit (0.00s)
=== RUN TestDepositInvalid
--- PASS: TestDepositInvalid (0.00s)
=== RUN TestWithdraw
--- PASS: TestWithdraw (0.00s)
PASS
ok github.com/msft/bank 0.250s
實作對帳單方法
讓我們撰寫一道方法,列印包含帳戶名稱、數字和餘額的對帳單。 但首先要建立 TestStatement
函式:
func TestStatement(t *testing.T) {
account := Account{
Customer: Customer{
Name: "John",
Address: "Los Angeles, California",
Phone: "(213) 555 0147",
},
Number: 1001,
Balance: 0,
}
account.Deposit(100)
statement := account.Statement()
if statement != "1001 - John - 100" {
t.Error("statement doesn't have the proper format")
}
}
當您執行 go test -v
時,您應該會在輸出中看到失敗的測試:
# github.com/msft/bank [github.com/msft/bank.test]
./bank_test.go:86:22: account.Statement undefined (type Account has no field or method Statement)
FAIL github.com/msft/bank [build failed]
讓我們撰寫 Statement
方法,其應會傳回字串。 (您稍後的挑戰為覆寫此方法)使用下列程式碼:
// Statement ...
func (a *Account) Statement() string {
return fmt.Sprintf("%v - %v - %v", a.Number, a.Name, a.Balance)
}
當您執行 go test -v
時,應該會看到測試已通過:
=== RUN TestAccount
--- PASS: TestAccount (0.00s)
=== RUN TestDeposit
--- PASS: TestDeposit (0.00s)
=== RUN TestDepositInvalid
--- PASS: TestDepositInvalid (0.00s)
=== RUN TestWithdraw
--- PASS: TestWithdraw (0.00s)
=== RUN TestStatement
--- PASS: TestStatement (0.00s)
PASS
ok github.com/msft/bank 0.328s
讓我們繼續下一節的內容,撰寫 Web API 公開 Statement
方法。