Menulis ujian integrasi dengan pangkalan data adalah penting untuk pembangunan aplikasi web, kerana ia meningkatkan keyakinan dalam kod kami dan memastikan aplikasi kami berfungsi seperti yang diharapkan. Walau bagaimanapun, menyediakan data olok-olok untuk ujian ini boleh menjadi mencabar, terutamanya dalam Go, yang tidak mempunyai pendekatan terbina dalam atau perpustakaan standard untuk tugasan ini. Artikel ini memperkenalkan perpustakaan gofacto, yang memudahkan proses membina data palsu dan memasukkannya ke dalam pangkalan data untuk ujian integrasi Go.
gofacto ialah perpustakaan Go yang memudahkan penciptaan dan penyisipan data palsu ke dalam pangkalan data. Ia menyediakan pendekatan intuitif untuk mentakrifkan skema data dan mengendalikan sisipan pangkalan data dengan cekap. Dengan gofacto, pembangun boleh menyediakan data ujian dengan cepat tanpa beban menulis kod boilerplate yang meluas, membolehkan mereka menumpukan pada menulis ujian yang bermakna.
Mari lihat perkara yang biasa kami lakukan semasa menulis ujian penyepaduan dengan pangkalan data dalam Go. Katakan kita mempunyai jadual bernama pengguna dalam pangkalan data, dan ia mempunyai skema berikut:
CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL );
Katakan kita ingin menguji fungsi bernama getUserByID yang mendapatkan semula pengguna dengan IDnya daripada jadual pengguna. Untuk menguji fungsi ini, kita perlu menyediakan beberapa data olok-olok dalam pangkalan data sebelum menguji fungsi ini. Begini cara biasa kami melakukannya:
type User struct { ID int Gender string Name string Email string } // build and insert mock user mockUser := User{ ID: 1, Gender: "male", Name: "Alice", Email: "aaa@gmail.com", } err := insertToDB(mockUser) // action result, err := getUserByID(mockUser.ID) // assertion // ...
insertToDB ialah fungsi yang memasukkan data palsu ke dalam pangkalan data. Ia mungkin menjadi sangat rumit jika kita menggunakan pertanyaan sql mentah.
Pendekatan ini nampaknya boleh diurus kerana skemanya mudah dan kami hanya berurusan dengan satu jadual.
Mari kita lihat kesnya apabila kita berurusan dengan dua jadual, pengguna dan siaran. Setiap pengguna boleh mempunyai berbilang siaran dan hubungan antara jadual diwujudkan oleh medan user_id dalam jadual siaran.
CREATE TABLE posts ( id INT PRIMARY KEY, user_id INT NOT NULL, title VARCHAR(255) NOT NULL, content TEXT NOT NULL, FOREIGN KEY (user_id) REFERENCES users(id) );
Katakan kita ingin menguji fungsi bernama getPostsByUserID yang mendapatkan semula semua siaran dengan ID pengguna daripada jadual siaran.
type Post struct { ID int UserID int Title string Content string } // build and insert mock user mockUser := User{ ID: 1, Gender: "male", Name: "Alice", Email: "aaa@gmail.com", } err := insertToDB(mockUser) // build and insert mock post mockPost1 := Post{ ID: 1, UserID: mockUser.ID, // manually set the foreign key Title: "Post 1", Content: "Content 1", } err = insertToDB(mockPost1) // build and insert mock post mockPost2 := Post{ ID: 2, UserID: mockUser.ID, // manually set the foreign key Title: "Post 2", Content: "Content 2", } err = insertToDB(mockPost2) // action result, err := getPostsByUserID(mockUser.ID) // assertion // ...
Kami mula-mula membuat pengguna dan kemudian membuat dua siaran untuk pengguna tersebut. Berbanding dengan contoh sebelumnya, ia menjadi lebih kompleks kerana kita berurusan dengan dua jadual dan mewujudkan hubungan antara mereka.
Bagaimana jika kita mahu membuat berbilang siaran dengan pengguna yang berbeza?
Kami perlu mencipta pengguna untuk setiap siaran dan ia memerlukan lebih banyak kod.
// build and insert mock user mockUser1 := User{ ID: 1, Gender: "male", Name: "Alice", Email: "aaa@gmail.com", } err := insertToDB(mockUser1) // build and insert mock user mockUser2 := User{ ID: 2, Gender: "female", Name: "Bob", Email: "bbb@gmail.com", } err = insertToDB(mockUser2) // build and insert mock post mockPost1 := Post{ ID: 1, UserID: mockUser1.ID, // manually set the foreign key Title: "Post 1", Content: "Content 1", } err = insertToDB(mockPost1) // build and insert mock post mockPost2 := Post{ ID: 2, UserID: mockUser2.ID, // manually set the foreign key Title: "Post 2", Content: "Content 2", } err = insertToDB(mockPost2) // action result, err := getPostsByUserID(mockUser1.ID) // assertion // ...
Ia menjadi lebih kompleks dan terdedah kepada ralat apabila kami perlu membuat berbilang data olok-olok dengan pengguna dan siaran yang berbeza.
Juga ambil perhatian bahawa kami hanya menggunakan skema mudah untuk tujuan demonstrasi, kod akan menjadi lebih kompleks dalam aplikasi dunia sebenar.
Dalam contoh di atas, terdapat beberapa masalah:
Sekarang, mari lihat bagaimana perpustakaan gofacto boleh membantu kami menyelesaikan masalah di atas, dan menjadikan keseluruhan proses lebih mudah.
Mari lihat contoh pertama dengan jadual pengguna.
// initialize a factory with User struct (also use `WithDB` to pass the database connection) f := gofacto.New(User{}).WithDB(db) // build and insert mock user mockUser, err := f.Build(ctx).Insert() // action result, err := getUserByID(mockUser.ID) // assertion // ...
Untuk menggunakan gofacto, kami mula-mula menggunakan fungsi Baharu untuk memulakan kilang baharu dengan Pengguna. Kerana kita perlu memasukkan data ke dalam pangkalan data, menggunakan WithDB untuk menghantar sambungan pangkalan data ke kilang.
Kemudian, kami menggunakan fungsi Bina untuk membina data olok-olok. Fungsi Sisipan memasukkan data olok-olok ke dalam pangkalan data dan mengembalikan data olok-olok yang telah dimasukkan ke dalam pangkalan data dengan ID yang ditambah secara automatik.
Ambil perhatian bahawa semua medan data olok-olok dijana secara rawak secara lalai. Tidak mengapa dalam kes ini kerana kami tidak mengambil berat tentang nilai medan.
Sekiranya kita ingin menentukan nilai medan, kita boleh menggunakan fungsi Tulis Ganti untuk menetapkan nilai medan.
mockUser, err := f.Build(ctx).Overwrite(User{Gender: "male"}).Insert() // mockUser.Gender == "male"
Apabila menggunakan fungsi Tulis Ganti, kita hanya perlu menentukan medan yang ingin kita timpa. Medan lain akan dijana secara rawak seperti biasa.
Mari kita lihat kes di mana kita ingin membuat berbilang siaran dengan seorang pengguna.
Untuk membuat gofacto mengetahui hubungan antara jadual, kita perlu menentukan tag yang betul dalam struct.
type Post struct { ID int UserID int `gofacto:"foreignKey,struct:User"` Title string Content string }
The tag tells gofacto that the UserID field is a foreign key that references the ID field of the User struct.
Now, we can create multiple posts with one user easily.
mockUser := User{} mockPosts, err := f.BuildList(ctx, 2).WithOne(&mockUser).Insert() // must pass pointer to the struct to `WithOne` // mockPosts[0].UserID == mockUser.ID // mockPosts[1].UserID == mockUser.ID // action result, err := getPostsByUserID(mockUser.ID) // assertion // ...
In order to create multiple posts, we use BuildList function with the number of posts that we want to create. Then, we use WithOne function to specify that all the posts belong to one user. The Insert function returns a list of posts that have been inserted into the database with the auto-incremented ID.
gofacto library makes sure all the fields are correctly set randomly, and the relationship between the tables is correctly established.
Let's see the case where we want to create multiple posts with different users.
mockUser1 := User{} mockUser2 := User{} mockPosts, err := f.BuildList(ctx, 2).WithMany([]interface{}{&mockUser1, &mockUser2}).Insert() // mockPosts[0].UserID == mockUser1.ID // mockPosts[1].UserID == mockUser2.ID // action result, err := getPostsByUserID(mockUser1.ID) // assertion // ...
We use WithMany function to specify that each post is associated with a different user.
We've seen how gofacto simplifies writing integration tests with databases in Go. It reduces boilerplate code and makes it easier to prepare mock data with multiple tables and establish relationships between them. Most importantly, gofacto abstracts away the complexity of preparing mock data, allowing developers to focus on writing meaningful tests. To start using gofacto in your Go projects, visit the GitHub repository for installation instructions and more detailed documentation.
As a new library developer, I'd love to hear your thoughts on gofacto! Any feedback, advice or criticism is appreciated. If you use it in your Go projects, please share your experience. Found a bug or have an idea? Open an issue on the gofacto GitHub repo. Want to contribute code? Pull requests are welcome! Your feedback and contributions will help improve gofacto and benefit the Go community. Thanks for checking it out!
Atas ialah kandungan terperinci Memudahkan Ujian Penyepaduan Go dengan gofacto: Kilang Berkuasa untuk Data Olok-olok. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!