データベースとの統合テストを記述することは、コードの信頼性を高め、アプリケーションが期待どおりに動作することを保証するため、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 // ...
異なるユーザーや投稿で複数のモックデータを作成する必要がある場合、より複雑になり、エラーが発生しやすくなります。
また、デモ目的で単純なスキーマのみを使用していることにも注意してください。実際のアプリケーションではコードはより複雑になります。
上記の例には、いくつかの問題があります:
それでは、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.
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!
以上がgofacto による Go 統合テストの簡素化: モックデータの強力なファクトリーの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。