Het bankkernpakket schrijven

Voltooid

Nu het basisproject samen met ons testbestand wordt uitgevoerd, gaan we beginnen met het schrijven van de code waarmee de functies en vereisten van de vorige les worden geïmplementeerd. Hier gaan we terug naar enkele onderwerpen die we eerder hebben besproken, zoals fouten, structuren en methoden.

Open het $GOPATH/src/bankcore/bank.go bestand, verwijder de Hello() functie en laten we beginnen met het schrijven van de kernlogica van ons online banksysteem.

Structuren maken voor klanten en accounts

Laten we beginnen met het maken van een Customer structuur waarin we de naam, het adres en het telefoonnummer hebben van een persoon die een bankklant wil worden. We hebben ook een structuur nodig voor de Account gegevens. Omdat een klant meer dan één account kan hebben, gaan we de klantgegevens insluiten in het accountobject. In principe gaan we maken wat we in de TestAccount test hebben gedefinieerd.

De structuren die we nodig hebben, kunnen eruitzien als in het volgende codevoorbeeld:

package bank

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

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

Wanneer u de opdracht nu uitvoert in uw go test -v terminal, ziet u dat de test wordt doorgegeven:

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

Deze test wordt doorgegeven omdat we de structuren voor Customer en Account. Nu we de structuren hebben, gaan we de methoden schrijven voor het toevoegen van de functies die we nodig hebben in de eerste versie van onze bank. Deze functies omvatten stortingen, intrekken en geld overmaken.

De stortingsmethode implementeren

We moeten beginnen met een methode om geld toe te voegen aan onze rekening. Maar voordat we dat doen, gaan we de TestDeposit functie in het bank_test.go bestand maken:

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

Wanneer u uitvoert go test -v, ziet u een mislukte test in de uitvoer:

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

Om aan de vorige test te voldoen, gaan we een Deposit methode maken voor onze Account structuur die een fout retourneert als het ontvangen bedrag gelijk is aan of lager is dan nul. Anders voegt u het bedrag toe dat u hebt ontvangen aan het saldo van de rekening.

Gebruik de volgende code voor de Deposit methode:

// 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
}

Wanneer u de test uitvoert go test -v, ziet u dat de test wordt doorgegeven:

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

U kunt ook een test schrijven die bevestigt dat u een foutmelding krijgt wanneer u een negatief bedrag probeert in te storten, zoals deze:

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

Wanneer u de go test -v opdracht uitvoert, ziet u dat de test wordt doorgegeven:

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

Notitie

Vanaf hier schrijven we één testcase voor elke methode. Maar u moet zoveel tests naar uw programma's schrijven als u zich vertrouwd voelt, zodat u zowel verwachte als onverwachte scenario's kunt behandelen. In dit geval wordt bijvoorbeeld de logica voor foutafhandeling getest.

De ingetrokken methode implementeren

Voordat we de Withdraw functionaliteit schrijven, gaan we de test hiervoor schrijven:

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

Wanneer u de go test -v opdracht uitvoert, ziet u een mislukte test in de uitvoer:

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

We gaan de logica voor de Withdraw methode implementeren, waarbij we het saldo van het account verminderen met het bedrag dat we als parameter ontvangen. Zoals we eerder hebben gedaan, moeten we valideren dat het getal dat we ontvangen groter is dan nul en dat het saldo in de rekening voldoende is.

Gebruik de volgende code voor de Withdraw methode:

// 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
}

Wanneer u de go test -v opdracht uitvoert, ziet u dat de test wordt doorgegeven:

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

De instructiemethode implementeren

Laten we een methode schrijven om de instructie af te drukken die de accountnaam, het nummer en het saldo bevat. Maar eerst gaan we de TestStatement functie maken:

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

Wanneer u uitvoert go test -v, ziet u een mislukte test in de uitvoer:

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

Laten we de Statement methode schrijven, die een tekenreeks moet retourneren. (U moet deze methode later overschrijven als een uitdaging.) Gebruik de volgende code:

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

Wanneer u de test uitvoert go test -v, ziet u dat de test wordt doorgegeven:

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

We gaan verder met de volgende sectie en schrijven de web-API die de Statement methode beschikbaar maakt.