>  기사  >  백엔드 개발  >  gofacto로 Go 통합 테스트 단순화: 모의 데이터를 위한 강력한 공장

gofacto로 Go 통합 테스트 단순화: 모의 데이터를 위한 강력한 공장

PHPz
PHPz원래의
2024-08-27 06:00:511020검색

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

데이터베이스와의 통합 테스트를 작성하는 것은 웹 애플리케이션 개발에 매우 ​​중요합니다. 이를 통해 코드에 대한 신뢰도가 높아지고 애플리케이션이 예상대로 작동하는지 확인할 수 있기 때문입니다. 그러나 이러한 테스트를 위한 모의 데이터 준비는 어려울 수 있으며, 특히 이 작업을 위한 기본 제공 접근 방식이나 표준 라이브러리가 부족한 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
// ...

다양한 사용자와 게시물로 여러 모의 데이터를 생성해야 하면 점점 더 복잡해지고 오류가 발생하기 쉽습니다.

또한 데모 목적으로 간단한 스키마만 사용하므로 실제 애플리케이션에서는 코드가 더 복잡해집니다.

 

문제는 무엇입니까?

위의 예에는 몇 가지 문제가 있습니다.

  • 데이터베이스에 모의 데이터를 준비하기 위해 상용구 코드를 많이 작성하세요.
    • 때로는 필드 값이 무엇인지 신경 쓰지 않고 각 필드에 올바른 값이 있는지 확인하면 됩니다.
  • 모의 데이터의 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 함수를 사용하여 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.

 

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.