Escritura del paquete principal del banco
Ahora que tenemos el proyecto base en ejecución junto con nuestro archivo de prueba, vamos a empezar a escribir el código que implementa las características y los requisitos de la unidad anterior. Aquí volvemos a tratar algunos asuntos de los que hablamos antes, como los errores, las estructuras y los métodos.
Abra el archivo de $GOPATH/src/bankcore/bank.go
, quite la función Hello()
y empiece a escribir la lógica principal del sistema de banco en línea.
Creación de estructuras para clientes y cuentas
Comencemos por crear una estructura Customer
donde tenemos el nombre, la dirección y el número de teléfono de una persona que quiere convertirse en un cliente de banco. Además, necesitamos una estructura para los datos de Account
. Dado que un cliente puede tener más de una cuenta, vamos a insertar la información del cliente en el objeto de cuenta. Básicamente, vamos a crear lo que definimos en la prueba TestAccount
.
Las estructuras que necesitamos podrían ser similares al siguiente ejemplo de código:
package bank
// Customer ...
type Customer struct {
Name string
Address string
Phone string
}
// Account ...
type Account struct {
Customer
Number int32
Balance float64
}
Al ejecutar el comando go test -v
en el terminal ahora, debería ver que la prueba se supera:
=== RUN TestAccount
--- PASS: TestAccount (0.00s)
PASS
ok github.com/msft/bank 0.094s
Esta prueba se supera porque hemos implementado las estructuras para Customer
y Account
. Ahora que tenemos las estructuras, vamos a escribir los métodos para agregar las características que necesitamos en la versión inicial de nuestro banco. Estas características incluyen el ingreso, la retirada y transferencia de dinero.
Implementación del método de ingreso de dinero
Necesitamos empezar con un método para permitir agregar dinero a nuestra cuenta. Pero antes de hacerlo, vamos a crear la función TestDeposit
en el archivo 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")
}
}
Al ejecutar go test -v
, debería ver una prueba que no se supera en la salida:
# 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 cumplir los requisitos de la prueba anterior, vamos a crear un método Deposit
en nuestra estructura Account
que devuelva un error si la cantidad recibida es igual o menor que cero. De lo contrario, basta con agregar la cantidad recibida al saldo de la cuenta.
Use el siguiente código para el 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
}
Al ejecutar go test -v
, debería ver que la prueba se supera:
=== RUN TestAccount
--- PASS: TestAccount (0.00s)
=== RUN TestDeposit
--- PASS: TestDeposit (0.00s)
PASS
ok github.com/msft/bank 0.193s
También puede escribir una prueba que confirme que aparece un error al intentar depositar una cantidad negativa, como esta:
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")
}
}
Al ejecutar el comando go test -v
, debería ver que la prueba se supera:
=== 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
Nota:
De aquí en adelante, escribiremos un caso de prueba para cada método. No obstante, debe escribir tantas pruebas en los programas como sea necesario para sentirse cómodo, de modo que pueda tratar tanto escenarios esperados como inesperados. Por ejemplo, en este caso, se prueba la lógica de control de errores.
Implementación del método de retirada de dinero
Antes de escribir la funcionalidad de Withdraw
, vamos a escribir la prueba para ella:
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")
}
}
Al ejecutar el comando go test -v
, debería ver una prueba que no se supera en la salida:
# 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 a implementar la lógica para el método Withdraw
, donde reducimos el saldo de la cuenta en la cantidad que recibimos como un parámetro. Como hicimos antes, es necesario validar que el número que recibimos es mayor que cero y que la cuenta tiene suficiente saldo.
Use el siguiente código para el 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
}
Al ejecutar el comando go test -v
, debería ver que la prueba se supera:
=== 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
Implementación del método de extracto
Vamos a escribir un método para imprimir el extracto que incluye el nombre, el número y el saldo de la cuenta. Pero primero, vamos a crear la función 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")
}
}
Al ejecutar go test -v
, debería ver una prueba que no se supera en la salida:
# 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 a escribir el método Statement
, que debe devolver una cadena. (Tiene que sobrescribir este método más adelante como un desafío). Use el siguiente código:
// Statement ...
func (a *Account) Statement() string {
return fmt.Sprintf("%v - %v - %v", a.Number, a.Name, a.Balance)
}
Al ejecutar go test -v
, debería ver que la prueba se supera:
=== 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
Pasemos a la sección siguiente y escribamos la API web que expone el método Statement
.