Pengujian Unit Lokal untuk Go

Pengujian unit lokal berjalan di dalam lingkungan Anda tanpa mengakses komponen jarak jauh. App Engine menyediakan utilitas pengujian yang menggunakan implementasi lokal Cloud Datastore dan layanan App Engine lainnya.

Layanan pengembangan menyimulasikan perilaku layanan yang sebenarnya secara lokal untuk pengujian. Misalnya, penggunaan datastore yang ditunjukkan dalam Menulis Pengujian Cloud Datastore dan Memcache memungkinkan Anda menguji kode datastore tanpa membuat permintaan apa pun ke datastore sebenarnya. Setiap entity yang disimpan selama pengujian unit datastore akan disimpan secara lokal dan dihapus setelah pengujian dijalankan. Anda dapat menjalankan pengujian kecil dan cepat tanpa dependensi pada datastore itu sendiri.

Dokumen ini menjelaskan cara menulis pengujian unit terhadap layanan App Engine lokal menggunakan paket pengujian Go.

Paket Pengujian Go

Anda dapat mengotomatiskan download, pembuatan, dan pengujian paket Go menggunakan alat goapp. goapp adalah bagian dari App Engine SDK untuk Go.

Kombinasi perintah goapp test dan paket testing Go standar dapat digunakan untuk menjalankan pengujian unit terhadap kode aplikasi Anda. Untuk latar belakang pengujian dengan Go, lihat bagian Pengujian Cara Menulis Kode Go dan referensi paket pengujian.

Pengujian unit terdapat dalam file yang berakhiran _test.go. Misalnya, Anda ingin menguji fungsi bernama composeNewsletter yang menampilkan *mail.Message. File newsletter_test.go berikut menunjukkan pengujian sederhana untuk fungsi tersebut:

package newsletter

import (
	"reflect"
	"testing"

	"google.golang.org/appengine/mail"
)

func TestComposeNewsletter(t *testing.T) {
	want := &mail.Message{
		Sender:  "newsletter@appspot.com",
		To:      []string{"User <user@example.com>"},
		Subject: "Weekly App Engine Update",
		Body:    "Don't forget to test your code!",
	}
	if msg := composeNewsletter(); !reflect.DeepEqual(msg, want) {
		t.Errorf("composeMessage() = %+v, want %+v", msg, want)
	}
}

Pengujian ini akan dipanggil menggunakan perintah goapp test dari dalam direktori paket:

goapp test

Alat goapp dapat ditemukan di direktori root App Engine SDK. Sebaiknya masukkan direktori ini dalam variabel PATH sistem Anda untuk mempermudah menjalankan pengujian.

Paket aetest

Banyak panggilan fungsi ke layanan App Engine yang memerlukan context.Context sebagai argumen. Paket appengine/aetest yang disediakan dengan SDK memungkinkan Anda membuat context.Context palsu untuk menjalankan pengujian menggunakan layanan yang disediakan di lingkungan pengembangan.

import (
	"testing"

	"google.golang.org/appengine/aetest"
)

func TestWithContext(t *testing.T) {
	ctx, done, err := aetest.NewContext()
	if err != nil {
		t.Fatal(err)
	}
	defer done()

	// Run code and tests requiring the context.Context using ctx.
	// ...
}

Panggilan ke aetest.NewContext akan memulai dev_appserver.py dalam subproses, yang akan digunakan untuk melayani panggilan API selama pengujian. Subproses ini akan dinonaktifkan dengan panggilan ke done.

Untuk kontrol lebih banyak atas instance yang mendasarinya, Anda dapat menggunakan aetest.NewInstance. Dengan demikian, Anda dapat membuat beberapa konteks, dan mengaitkan konteks tersebut dengan objek http.Request.

import (
	"errors"
	"testing"

	"golang.org/x/net/context"

	"google.golang.org/appengine"
	"google.golang.org/appengine/aetest"
	"google.golang.org/appengine/datastore"
)

func TestMyFunction(t *testing.T) {
	inst, err := aetest.NewInstance(nil)
	if err != nil {
		t.Fatalf("Failed to create instance: %v", err)
	}
	defer inst.Close()

	req1, err := inst.NewRequest("GET", "/gophers", nil)
	if err != nil {
		t.Fatalf("Failed to create req1: %v", err)
	}
	c1 := appengine.NewContext(req1)

	req2, err := inst.NewRequest("GET", "/herons", nil)
	if err != nil {
		t.Fatalf("Failed to create req2: %v", err)
	}
	c2 := appengine.NewContext(req2)

	// Run code and tests with *http.Request req1 and req2,
	// and context.Context c1 and c2.
	// ...
}

Baca referensi paket aetest untuk mengetahui informasi selengkapnya.

Menulis pengujian Cloud Datastore dan memcache

Pengujian kode yang menggunakan datastore atau memcache dapat dilakukan dengan mudah setelah Anda membuat context.Context dengan paket aetest: dalam panggilan pengujian aetest.NewContext, untuk membuat konteks yang akan diteruskan ke fungsi dalam uji coba.

Aplikasi demo transaction di SDK memiliki contoh struktur kode untuk memungkinkan pengujian, dan cara menguji kode yang menggunakan datastore:

func TestWithdrawLowBal(t *testing.T) {
	ctx, done, err := aetest.NewContext()
	if err != nil {
		t.Fatal(err)
	}
	defer done()
	key := datastore.NewKey(ctx, "BankAccount", "", 1, nil)
	if _, err := datastore.Put(ctx, key, &BankAccount{100}); err != nil {
		t.Fatal(err)
	}

	err = withdraw(ctx, "myid", 128, 0)
	if err == nil || err.Error() != "insufficient funds" {
		t.Errorf("Error: %v; want insufficient funds error", err)
	}

	b := BankAccount{}
	if err := datastore.Get(ctx, key, &b); err != nil {
		t.Fatal(err)
	}
	if bal, want := b.Balance, 100; bal != want {
		t.Errorf("Balance %d, want %d", bal, want)
	}
}

Pengujian ini dapat dijalankan menggunakan perintah goapp test:

goapp test ./demos/transaction

Pengujian untuk memcache mengikuti pola yang sama: siapkan status awal memcache dalam pengujian, jalankan fungsi yang sedang diuji, dan pastikan fungsi telah mengkueri/mengubah memcache seperti yang Anda harapkan.