文档
参考
功能
模拟

测试模拟

在为调用 Go 客户端使用的方法的函数编写测试时,通常需要运行一个真实的数据库才能使这些测试正常工作。虽然这对于集成测试是可以接受的,但由于需要重置和迁移数据库、播种数据,然后关闭所有内容,因此测试代码可能更难。此外,这会导致测试运行速度非常慢。

Prisma 提供了原生模拟,以便在单元测试中注入任何你想要的内容。这样,你可以为每个查询定义要返回的结果,然后使用这些信息测试你的函数。它们也很快,因为不需要真实的数据库,你只需自己定义函数应该返回什么。

这些示例使用以下 Prisma 模式

model Post {
  id    String   @default(cuid()) @id
  title String
}

测试结果

函数 GetPostTitle 充当你的解析器;例如,它可以是 API 路由中调用的函数。

要编写单元测试,你需要创建一个新的 Prisma 模拟客户端,定义你的期望,然后运行你的实际测试。期望包括你期望的精确查询或查询,以及应该返回的结果。

// main.go
func GetPostTitle(ctx context.Context, client *PrismaClient, postID string) (string, error) {
  post, err := client.Post.FindUnique(
    db.Post.ID.Equals(postID),
  ).Exec(ctx)
  if err != nil {
    return "", fmt.Errorf("error fetching post: %w", err)
  }
 
  return post.Title, nil
}
 
// main_test.go
func TestGetPostTitle_returns(t *testing.T) {
  // create a new mock
  // this returns a mock prisma `client` and a `mock` object to set expectations
  client, mock, ensure := NewMock()
  // defer calling ensure, which makes sure all of the expectations were met and actually called
  // calling this makes sure that an error is returned if there was no query happening for a given expectation
  // and makes sure that all of them succeeded
  defer ensure(t)
 
  expected := db.PostModel{
    InnerPost: db.InnerPost{
      ID:   "123",
      Title: "foo",
    },
  }
 
  // start the expectation
  mock.Post.Expect(
    // define your exact query as in your tested function
    // call it with the exact arguments which you expect the function to be called with
    // you can copy and paste this from your tested function, and just put specific values into the arguments
    client.Post.FindUnique(
      db.Post.ID.Equals("123"),
    ),
  ).Returns(expected) // sets the object which should be returned in the function call
 
  // mocking set up is done; let's define the actual test now
  title, err := GetPostTitle(context.Background(), client, "123")
  if err != nil {
    t.Fatal(err)
  }
 
  if title != "foo" {
    t.Fatalf("title expected to be foo but is %s", title)
  }
}

测试错误

你还可以使用 Errors 函数模拟客户端为给定查询返回错误。

// main_test.go
func TestGetPostTitle_error(t *testing.T) {
  client, mock, ensure := NewMock()
  defer ensure(t)
 
  mock.Post.Expect(
    client.Post.FindUnique(
      db.Post.ID.Equals("123"),
    ),
  ).Errors(db.ErrNotFound)
 
  _, err := GetPostTitle(context.Background(), client, "123")
  if !errors.Is(err, ErrNotFound) {
    t.Fatalf("error expected to return ErrNotFound but is %s", err)
  }
}