데이터베이스와의 통합 테스트를 작성하는 것은 웹 애플리케이션 개발에 매우 중요합니다. 이를 통해 코드에 대한 신뢰도가 높아지고 애플리케이션이 예상대로 작동하는지 확인할 수 있기 때문입니다. 그러나 이러한 테스트를 위한 모의 데이터 준비는 어려울 수 있으며, 특히 이 작업을 위한 기본 제공 접근 방식이나 표준 라이브러리가 부족한 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 );
사용자 테이블에서 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 쿼리를 사용한다면 훨씬 복잡해질 수 있습니다.
이 접근 방식은 스키마가 단순하고 테이블 하나만 다루기 때문에 관리하기 쉬운 것 같습니다.
사용자와 게시물이라는 두 개의 테이블을 처리하는 경우를 살펴보겠습니다. 각 사용자는 여러 게시물을 가질 수 있으며 테이블 간의 관계는 게시물 테이블의 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) );
posts 테이블에서 사용자 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 // ...
먼저 사용자를 생성한 다음 해당 사용자에 대한 두 개의 게시물을 생성합니다. 앞의 예와 비교하면 두 개의 테이블을 다루며 이들 사이의 관계를 설정하기 때문에 더욱 복잡해집니다.
다른 사용자로 여러 게시물을 만들고 싶다면 어떻게 해야 하나요?
각 게시물에 대해 사용자를 생성해야 하며, 이를 위해서는 더 많은 코드가 필요합니다.
// 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 함수를 사용하여 User로 새 팩토리를 초기화합니다. 데이터베이스에 데이터를 삽입해야 하기 때문에 WithDB를 사용하여 데이터베이스 연결을 공장에 전달합니다.
그런 다음 Build 함수를 사용하여 모의 데이터를 빌드합니다. Insert 함수는 모의 데이터를 데이터베이스에 삽입하고, 데이터베이스에 삽입된 모의 데이터를 자동 증가된 ID로 반환합니다.
모의 데이터의 모든 필드는 기본적으로 무작위로 생성됩니다. 이 경우에는 필드 값에 관심이 없기 때문에 괜찮습니다.
필드 값을 지정하려는 경우 덮어쓰기 기능을 사용하여 필드 값을 설정할 수 있습니다.
mockUser, err := f.Build(ctx).Overwrite(User{Gender: "male"}).Insert() // mockUser.Gender == "male"
덮어쓰기 기능을 사용할 때는 덮어쓰려는 필드만 지정하면 됩니다. 다른 필드는 평소와 같이 무작위로 생성됩니다.
한 명의 사용자로 여러 개의 게시물을 작성하고 싶은 경우를 살펴보겠습니다.
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 중국어 웹사이트의 기타 관련 기사를 참조하세요!