Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Memudahkan Ujian Penyepaduan Go dengan gofacto: Kilang Berkuasa untuk Data Olok-olok

Memudahkan Ujian Penyepaduan Go dengan gofacto: Kilang Berkuasa untuk Data Olok-olok

PHPz
PHPzasal
2024-08-27 06:00:511020semak imbas

Simplifying Go Integration Tests with gofacto: A Powerful Factory for Mock Data

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.

 

Apa itu gofacto?

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.

 

Sebelum menggunakan gofacto

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.

 

Apakah masalahnya?

Dalam contoh di atas, terdapat beberapa masalah:

  • Tulis banyak kod boilerplate untuk menyediakan data palsu dalam pangkalan data
    • Kadang-kadang, kita tidak kisah apa nilai medan, kita cuma perlu pastikan ada nilai yang betul dalam setiap medan.
  • Kod keras nilai ID dalam data palsu
    • Adalah bukan amalan yang baik untuk mengekodkan keras nilai ID dalam data palsu kerana ID biasanya dinaikkan secara automatik dalam pangkalan data.
  • Mewujudkan perhubungan antara jadual secara manual
    • Ini menjadikan kod ujian menyusahkan dan terdedah kepada ralat, terutamanya apabila mencipta data palsu dengan berbilang jadual berkaitan.

 

Menggunakan gofacto

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.

 

Summary

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.

 

Feedback and Further Development

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!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn