Escrever o pacote de núcleo do banco
Agora que temos o projeto base em execução junto com nosso arquivo de teste, vamos começar a escrever o código que implementa os recursos e requisitos da unidade anterior. Aqui, revisitamos alguns assuntos que discutimos anteriormente, como erros, estruturas e métodos.
Abra o arquivo $GOPATH/src/bankcore/bank.go
, remova a função Hello()
e vamos começar a escrever a lógica do núcleo do nosso sistema bancário online.
Criar estruturas para clientes e contas
Vamos começar criando uma estrutura Customer
na qual temos o nome, o endereço e o número de telefone de uma pessoa que quer se tornar um cliente bancário. Além disso, precisamos de uma estrutura para os dados Account
. Como um cliente pode ter mais de uma conta, vamos inserir as informações do cliente no objeto de conta. Basicamente, vamos criar o que definimos no teste TestAccount
.
As estruturas necessárias podem ser semelhantes ao seguinte exemplo de código:
package bank
// Customer ...
type Customer struct {
Name string
Address string
Phone string
}
// Account ...
type Account struct {
Customer
Number int32
Balance float64
}
Quando você executar o comando go test -v
no seu terminal agora, verá que o teste é aprovado:
=== RUN TestAccount
--- PASS: TestAccount (0.00s)
PASS
ok github.com/msft/bank 0.094s
Esse teste foi aprovado porque implementamos as estruturas para Customer
e Account
. Agora que temos as estruturas, vamos escrever os métodos para adicionar os recursos necessários na versão inicial do nosso banco. Esses recursos incluem o depósito, a retirada e a transferência de dinheiro.
Implementar o método de depósito
Precisamos começar com um método para permitir a adição de dinheiro à nossa conta. Mas, antes de fazermos isso, vamos criar a função TestDeposit
no arquivo bank_test.go
:
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")
}
}
Quando você executar go test -v
, deverá ver um teste com falha no resultado:
# 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]
Para satisfazer ao teste anterior, vamos criar um método Deposit
para nossa estrutura Account
que retornará um erro se o valor recebido for igual ou menor que zero. Caso contrário, basta adicionar o valor recebido ao saldo da conta.
Use o seguinte código para o método 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
}
Quando você executar go test -v
, verá que o teste é aprovado:
=== RUN TestAccount
--- PASS: TestAccount (0.00s)
=== RUN TestDeposit
--- PASS: TestDeposit (0.00s)
PASS
ok github.com/msft/bank 0.193s
Você também pode escrever um teste que confirma que você recebe um erro ao tentar depositar um valor negativo, como este:
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")
}
}
Quando você executar o comando go test -v
, verá que o teste é aprovado:
=== 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
Observação
Daqui em diante, vamos escrever um caso de teste para cada método. Mas você deve escrever quantos testes para seus programas você quiser. Assim, você pode abordar cenários esperados e inesperados. Por exemplo, nesse caso, a lógica de tratamento de erro é testada.
Implementar o método de saque
Antes de escrevermos a funcionalidade Withdraw
, vamos escrever o teste para ela:
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")
}
}
Quando você executar o comando go test -v
, deverá ver um teste com falha no resultado:
# 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]
Vamos implementar a lógica para o método Withdraw
, no qual reduzimos o valor que recebemos como parâmetro do saldo da conta. Como fizemos anteriormente, precisamos validar que o número que recebemos é maior que zero e que o saldo na conta é suficiente.
Use o seguinte código para o método 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
}
Quando você executar o comando go test -v
, verá que o teste é aprovado:
=== 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
Implementar o método de extrato
Vamos escrever um método para imprimir o extrato que inclua o nome da conta, o número e o saldo. Mas, primeiro, vamos criar a função 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")
}
}
Quando você executar go test -v
, deverá ver um teste com falha no resultado:
# 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]
Vamos escrever o método Statement
, que deve retornar uma cadeia de caracteres. (Você precisará substituir esse método mais tarde como um desafio.) Use o seguinte código:
// Statement ...
func (a *Account) Statement() string {
return fmt.Sprintf("%v - %v - %v", a.Number, a.Name, a.Balance)
}
Quando você executar go test -v
, verá que o teste é aprovado:
=== 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
Vamos passar para a próxima seção e escrever a API Web que expõe o método Statement
.