gofacto による Go 統合テストの簡素化: モックデータの強力なファクトリー

PHPz
リリース: 2024-08-27 06:00:51
オリジナル
986 人が閲覧しました

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

データベースとの統合テストを記述することは、コードの信頼性を高め、アプリケーションが期待どおりに動作することを保証するため、Web アプリケーション開発にとって非常に重要です。ただし、これらのテスト用のモック データの準備は、特に Go では、このタスク用の組み込みアプローチや標準ライブラリが不足しているため、困難になる可能性があります。この記事では、モック データを構築し、それを Go 統合テスト用のデータベースに挿入するプロセスを簡素化する gofacto ライブラリを紹介します。

ゴファクトとは何ですか?

gofacto は、モック データの作成とデータベースへの挿入を簡素化する Go ライブラリです。データ スキーマを定義し、データベースの挿入を効率的に処理するための直感的なアプローチを提供します。 gofacto を使用すると、開発者は広範な定型コードを記述する負担を負わずにテスト データを迅速に準備できるため、有意義なテストの作成に集中できます。

ゴファクトを使用する前に

Go でデータベースとの統合テストを作成するときに通常何を行うかを見てみましょう。データベースに users という名前のテーブルがあり、次のスキーマがあるとします。

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL
);
ログイン後にコピー

users テーブルから ID によってユーザーを取得する getUserByID という名前の関数をテストするとします。この関数をテストするには、この関数をテストする前にデータベースに模擬データを準備する必要があります。通常のやり方は次のとおりです:

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 は、データベースにモックデータを挿入する関数です。生の SQL クエリを使用している場合は、非常に複雑になる可能性があります。

スキーマが単純で、扱うテーブルが 1 つだけであるため、このアプローチは管理可能であると思われます。

2 つのテーブル、ユーザーと投稿を扱う場合を見てみましょう。各ユーザーは複数の投稿を持つことができ、テーブル間の関係は、posts テーブルの user_id フィールドによって確立されます。

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)
);
ログイン後にコピー

投稿テーブルからユーザーの ID によってすべての投稿を取得する getPostsByUserID という名前の関数をテストするとします。

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
// ...
ログイン後にコピー

最初にユーザーを作成し、次にそのユーザーに対して 2 つの投稿を作成します。前の例と比較すると、2 つのテーブルを処理し、それらの間の関係を確立するため、より複雑になります。

異なるユーザーで複数の投稿を作成したい場合はどうすればよいですか?
投稿ごとにユーザーを作成する必要があり、さらに多くのコードが必要です。

// 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
// ...
ログイン後にコピー

異なるユーザーや投稿で複数のモックデータを作成する必要がある場合、より複雑になり、エラーが発生しやすくなります。

また、デモ目的で単純なスキーマのみを使用していることにも注意してください。実際のアプリケーションではコードはより複雑になります。

問題点は何ですか?

上記の例には、いくつかの問題があります:

  • データベース内に模擬データを準備するための定型コードを大量に作成する
    • 場合によっては、フィールドの値が何であるかは気にせず、各フィールドに正しい値があることを確認するだけで十分な場合があります。
  • モックデータ内のIDの値をハードコードする
    • ID は通常、自動的にインクリメントされるため、モック データに ID の値をハードコーディングすることはお勧めできません。 データベース。
  • テーブル間の関係を手動で確立する
    • これにより、特に複数の関連テーブルを含むモック データを作成する場合、テスト コードが煩雑になり、エラーが発生しやすくなります。

ゴファクトの使用

それでは、gofacto ライブラリがどのように上記の問題を解決し、プロセス全体を簡素化するのに役立つかを見てみましょう。

users テーブルを使用した最初の例を見てみましょう。

// 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
// ...
ログイン後にコピー

gofacto を使用するには、まず New 関数を使用して、ユーザーで新しいファクトリを初期化します。データをデータベースに挿入する必要があるため、WithDB を使用してデータベース接続をファクトリに渡します。
次に、Build 関数を使用してモックデータを構築します。 Insert 関数は、モック データをデータベースに挿入し、データベースに挿入されたモック データを自動インクリメントされた ID とともに返します。

デフォルトでは、モック データのすべてのフィールドがランダムに生成されることに注意してください。この場合、フィールドの値は気にしないので問題ありません。

フィールドの値を指定したい場合は、上書き機能を使用してフィールドの値を設定できます。

mockUser, err := f.Build(ctx).Overwrite(User{Gender: "male"}).Insert()
// mockUser.Gender == "male"
ログイン後にコピー

上書き機能を使用する場合、上書きしたいフィールドを指定するだけで済みます。他のフィールドは通常どおりランダムに生成されます。

1 人のユーザーで複数の投稿を作成する場合を見てみましょう。
gofacto にテーブル間の関係を認識させるには、構造体内に正しいタグを定義する必要があります。

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!

以上がgofacto による Go 統合テストの簡素化: モックデータの強力なファクトリーの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!