Skriva bankkärnpaketet

Slutförd

Nu när basprojektet körs tillsammans med vår testfil ska vi börja skriva koden som implementerar den tidigare enhetens funktioner och krav. Vi återkommer till några ämnen som vi har diskuterat, till exempel fel, strukturer och metoder.

$GOPATH/src/bankcore/bank.go Öppna filen, ta bort Hello() funktionen och börja skriva kärnlogik i vårt onlinebanksystem.

Skapa strukturer för kunder och konton

Vi börjar med att skapa en Customer struktur där vi har namn, adress och telefonnummer från en person som vill bli bankkund. Dessutom behöver vi en struktur för Account data. Eftersom en kund kan ha fler än ett konto ska vi bädda in kundinformationen i kontoobjektet. I grund och botten ska vi skapa det vi definierade i TestAccount testet.

De strukturer som vi behöver kan se ut som i följande kodexempel:

package bank

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

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

När du kör kommandot i terminalen go test -v nu bör du se att testet skickas:

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

Det här testet skickas eftersom vi har implementerat strukturerna för Customer och Account. Nu när vi har strukturerna ska vi skriva metoderna för att lägga till de funktioner som vi behöver i den första versionen av vår bank. Dessa funktioner inkluderar insättning, uttag och överföring av pengar.

Implementera insättningsmetoden

Vi måste börja med en metod som gör det möjligt att lägga till pengar på vårt konto. Men innan vi gör det ska vi skapa TestDeposit funktionen i bank_test.go filen:

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

När du kör go test -vbör du se ett misslyckat test i utdata:

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

För att uppfylla föregående test ska vi skapa en Deposit metod för vår Account struktur som returnerar ett fel om det mottagna beloppet är lika med eller lägre än noll. Annars lägger du bara till det mottagna beloppet i saldot för kontot.

Använd följande kod för Deposit metoden:

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

När du kör go test -vbör du se att testet skickas:

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

Du kan också skriva ett test som bekräftar att du får ett fel när du försöker sätta in ett negativt belopp, så här:

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

När du kör go test -v kommandot bör du se att testet skickas:

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

Kommentar

Härifrån skriver vi ett testfall för varje metod. Men du bör skriva så många tester till dina program som du känner dig bekväm med, så att du kan täcka både förväntade och oväntade scenarier. I det här fallet testas till exempel felhanteringslogik.

Implementera återdragningsmetoden

Innan vi skriver återdragningsfunktionen ska vi skriva testet för det:

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

När du kör go test -v kommandot bör du se ett misslyckat test i utdata:

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

Nu ska vi implementera logiken Withdraw för metoden, där vi ska minska saldot för kontot med det belopp som vi får som parameter. Precis som vi gjorde tidigare måste vi verifiera att det antal vi får är större än noll och att saldot i kontot räcker.

Använd följande kod för Withdraw metoden:

// 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 greater than the account's balance")
    }

    a.Balance -= amount
    return nil
}

När du kör go test -v kommandot bör du se att testet skickas:

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

Implementera instruktionsmetoden

Nu ska vi skriva en metod för att skriva ut -instruktionen som innehåller kontonamnet, numret och saldot. Men först ska vi skapa TestStatement funktionen:

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

När du kör go test -vbör du se ett misslyckat test i utdata:

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

Nu ska vi skriva Statement metoden, som ska returnera en sträng. (Du måste skriva över den här metoden senare som en utmaning.) Använd följande kod:

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

När du kör go test -vbör du se att testet skickas:

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

Nu går vi vidare till nästa avsnitt för att skriva webb-API:et Statement för att exponera metoden.