Scrivere il pacchetto principale del programma per la banca
Ora che il progetto di base è in esecuzione insieme al file di test, è possibile iniziare a scrivere il codice che implementa le funzionalità e i requisiti dell'unità precedente. Qui rivisitiamo alcuni argomenti illustrati in precedenza, ad esempio errori, strutture e metodi.
Aprire il file $GOPATH/src/bankcore/bank.go
, rimuovere la funzione Hello()
e iniziare a scrivere la logica di base del sistema di online banking.
Creare le strutture per clienti e conti
Iniziamo creando una Customer
struttura in cui abbiamo il nome, l'indirizzo e il numero di telefono di una persona che vuole diventare un cliente bancario. Occorre anche una struttura per i dati dei conti (Account
). Poiché un cliente può avere più di un conto, si incorporeranno le informazioni sul cliente nell'oggetto account. In pratica, si creerà ciò che è stato definito nel test TestAccount
.
Le strutture necessarie potrebbero avere un aspetto simile all'esempio di codice seguente:
package bank
// Customer ...
type Customer struct {
Name string
Address string
Phone string
}
// Account ...
type Account struct {
Customer
Number int32
Balance float64
}
Quando si esegue il comando go test -v
nel terminale, si dovrebbe vedere che il test viene superato:
=== RUN TestAccount
--- PASS: TestAccount (0.00s)
PASS
ok github.com/msft/bank 0.094s
Questo test viene superato perché sono state implementate le strutture per Customer
e Account
. Ora che le strutture sono al loro posto, si procederà con la scrittura dei metodi per aggiungere le funzionalità necessarie nella versione iniziale del sistema di online banking. Queste funzionalità includono il versamento, il prelievo e il trasferimento di denaro.
Implementare il metodo di versamento
Il primo metodo da implementare è quello che consente di aggiungere denaro al conto. Prima di procedere, però, occorre creare la funzione TestDeposit
nel file 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 si esegue go test -v
, nell'output dovrebbe essere visualizzato un test non superato:
# 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]
Per soddisfare il test riportato sopra, si creerà un metodo Deposit
per la struttura Account
che restituisca un errore se l'importo ricevuto è uguale o minore di zero. In caso contrario, l'importo ricevuto verrà semplicemente aggiunto al saldo del conto.
Usare il codice seguente per il metodo 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 si esegue go test -v
, si dovrebbe vedere che il test viene superato:
=== RUN TestAccount
--- PASS: TestAccount (0.00s)
=== RUN TestDeposit
--- PASS: TestDeposit (0.00s)
PASS
ok github.com/msft/bank 0.193s
È anche possibile scrivere un test che verifichi che si riceva un messaggio di errore se si cerca di versare un importo negativo, come nel codice seguente:
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 si esegue il comando go test -v
, si dovrebbe vedere che il test viene superato:
=== 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
Da questo punto in poi, si scriverà un test case per ogni metodo. È tuttavia consigliabile scrivere il maggior numero possibile di test per i propri programmi, in modo da coprire sia gli scenari previsti che quelli imprevisti. In questo caso, ad esempio, viene testata la logica di gestione degli errori.
Implementare il metodo di prelievo
Prima di scrivere la Withdraw
funzionalità, scrivere il test:
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 si esegue il comando go test -v
, nell'output dovrebbe essere visualizzato un test non superato:
# 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]
Implementare la logica per il Withdraw
metodo, in cui si riduce il saldo del conto in base all'importo ricevuto come parametro. Come è già stato fatto, è necessario verificare che il numero ricevuto sia maggiore di zero e che il saldo del conto sia sufficiente.
Usare il codice seguente per il metodo 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 si esegue il comando go test -v
, si dovrebbe vedere che il test viene superato:
=== 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
Implementare il metodo per la stampa dell'estratto conto
Si scriverà ora un metodo per stampare l'estratto conto che include il nome, il numero e il saldo del conto. Ma prima occorre creare la funzione 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 si esegue go test -v
, nell'output dovrebbe essere visualizzato un test non superato:
# 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]
Scrivere ora il metodo Statement
, che dovrebbe restituire una stringa. È necessario sovrascrivere questo metodo in un secondo momento come sfida. Usare il codice seguente:
// Statement ...
func (a *Account) Statement() string {
return fmt.Sprintf("%v - %v - %v", a.Number, a.Name, a.Balance)
}
Quando si esegue go test -v
, si dovrebbe vedere che il test viene superato:
=== 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
Si passerà alla sezione successiva e si scriverà l'API Web che espone il Statement
metodo .