Écrire le package principal de la banque

Effectué

Maintenant que nous avons le projet de base en cours d’exécution avec notre fichier de test, commençons par écrire le code qui implémente les fonctionnalités et les exigences de l’unité précédente. Ici, nous revisitons quelques sujets abordés plus tôt, tels que les erreurs, structures et méthodes.

Ouvrez le fichier $GOPATH/src/bankcore/bank.go, supprimez la fonction Hello(), puis commencez à écrire la logique principale de notre système bancaire.

Créer des structures pour les clients et les comptes

Commençons par créer une structure Customer dans laquelle nous avons le nom, l’adresse et le numéro de téléphone d’une personne qui souhaite devenir client de la banque. Nous avons également besoin d’une structure pour les données de Account. Étant donné qu’un client peut avoir plusieurs comptes, nous allons incorporer les informations client dans l’objet du compte. Fondamentalement, nous allons créer ce que nous avons défini dans le test TestAccount.

Les structures dont nous avons besoin peuvent ressembler à l’exemple de code suivant :

package bank

// Customer ...
type Customer struct {
    Name    string
    Address string
    Phone   string
}

// Account ...
type Account struct {
    Customer
    Number  int32
    Balance float64
}

Quand vous exécutez la commande go test -v dans votre terminal, vous devez voir que le test réussit :

=== RUN   TestAccount
--- PASS: TestAccount (0.00s)
PASS
ok      github.com/msft/bank    0.094s

Ce test réussit, car nous avons implémenté les structures pour Customer et Account. Maintenant que nous disposons des structures, nous allons écrire les méthodes permettant d’ajouter les fonctionnalités dont nous avons besoin dans la version initiale de notre banque. Ces fonctionnalités incluent le dépôt, le retrait et le transfert d’argent.

Implémenter la méthode de dépôt

Nous devons commencer par une méthode qui permet d’ajouter de l’argent à notre compte. Mais avant cela, nous allons créer la fonction TestDeposit dans le fichier 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")
    }
}

Lorsque vous exécutez go test -v, vous devez voir un test d’échec dans le résultat :

# 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]

Pour satisfaire le test précédent, nous allons créer une méthode Deposit pour notre structure Account qui retourne une erreur si le montant reçu est inférieur ou égal à zéro. Dans le cas contraire, ajoutez le montant reçu au solde du compte.

Utilisez le code suivant pour la méthode 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
}

Lorsque vous exécutez go test -v, vous devez voir que le test est réussi :

=== RUN   TestAccount
--- PASS: TestAccount (0.00s)
=== RUN   TestDeposit
--- PASS: TestDeposit (0.00s)
PASS
ok      github.com/msft/bank    0.193s

Vous pouvez également écrire un test qui confirme que vous recevez une erreur lorsque vous essayez de déposer un montant négatif, comme suit :

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")
    }
}

Lorsque vous exécutez go test -v, vous devez voir que le test est réussi :

=== 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

Notes

À partir de là, nous allons écrire un cas de test pour chaque méthode. Mais vous devez écrire autant de tests que vous le souhaitez dans vos programmes. Vous pouvez ainsi couvrir les scénarios attendus et inattendus. Par exemple, dans ce cas, la logique de gestion des erreurs est testée.

Implémenter la méthode de retrait

Avant d’écrire la fonctionnalité Withdraw, nous allons écrire le test pour celle-ci :

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")
    }
}

Quand vous exécutez la commande go test -v, vous devez voir un test ayant échoué dans la sortie :

# 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]

Nous allons implémenter la logique de la méthode Withdraw, où nous diminuons le solde du compte en fonction de la valeur que nous recevons en tant que paramètre. Comme nous l’avons fait précédemment, nous devons confirmer que le nombre que nous recevons est supérieur à zéro et que le solde du compte est suffisant.

Utilisez le code suivant pour la méthode 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
}

Lorsque vous exécutez go test -v, vous devez voir que le test est réussi :

=== 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

Implémenter la méthode d’instruction

Nous allons écrire une méthode pour imprimer l’instruction qui comprend le nom, le numéro et le solde du compte. Commençons donc par créer la fonction 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")
    }
}

Lorsque vous exécutez go test -v, vous devez voir un test d’échec dans le résultat :

# 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]

Nous allons écrire la méthode Statement, qui doit retourner une chaîne. (Vous devrez remplacer cette méthode en tant que défi un peu plus tard.) Utilisez le code suivant :

// Statement ...
func (a *Account) Statement() string {
    return fmt.Sprintf("%v - %v - %v", a.Number, a.Name, a.Balance)
}

Lorsque vous exécutez go test -v, vous devez voir que le test est réussi :

=== 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

Passons à la section suivante pour écrire l’API web qui expose la méthode Statement.