编写银行核心程序包
现在,我们已经有了与我们的测试文件一起运行的基础项目,接下来我们将开始编写代码来实现上一个单元的功能和需求。 本文回顾了之前讨论过的几个主题,例如错误、结构和方法。
打开 $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
让我们转到下一部分,并编写公开 Statement
方法的 Web API。