数据库断言

本指南涵盖在 AdonisJS 测试中断言数据库状态。你将学习如何:

  • 配置数据库断言插件
  • 断言表中的行存在或缺失
  • 检查行数以及空表
  • 验证模型实例存在或已被删除

概述

在测试修改数据库的功能时,你经常需要验证最终的状态:行被创建了吗?它被删除了吗?记录的数量是否恰好正确?Lucid 提供了一个 Japa 插件,将数据库断言方法直接添加到测试上下文中,这样你就可以在不编写原始查询的情况下验证数据库状态。

该插件在测试上下文上暴露了一个 db 对象,其方法包括 assertHasassertMissingassertCount,以及模型级别的断言。每个方法都会查询数据库,并在断言失败时抛出带有清晰消息的 AssertionError

设置

在你的 tests/bootstrap.ts 文件中注册 dbAssertions 插件。

tests/bootstrap.ts
import app from '@adonisjs/core/services/app'
import { dbAssertions } from '@adonisjs/lucid/plugins/db'

export const plugins: Config['plugins'] = [
  assert(),
  pluginAdonisJS(app),
  apiClient(),
  dbAssertions(app),
]

注册后,db 属性即可在测试上下文中使用。你可以通过解构测试回调参数来访问它。

tests/functional/users.spec.ts
import { test } from '@japa/runner'

test('creates a user', async ({ db }) => {
  // 使用 db.assertHas、db.assertMissing 等。
})

断言行存在

assertHas 方法检查表中是否至少有一行与给定的数据匹配。传入一个表名和一个用于匹配的对象(由列/值对组成)。

tests/functional/users.spec.ts
import { test } from '@japa/runner'
import testUtils from '@adonisjs/core/services/test_utils'

test.group('Users', (group) => {
  group.each.setup(() => testUtils.db().truncate())

  test('registers a new user', async ({ client, db }) => {
    await client.post('/register').json({
      email: 'jul@test.com',
      password: 'secret123',
    })

    // 当至少有一行匹配时通过
    await db.assertHas('users', { email: 'jul@test.com' })
  })
})

你可以传入可选的第三个参数,以断言匹配行的确切数量。

tests/functional/users.spec.ts
test('promotes multiple users to admin', async ({ client, db }) => {
  await User.createMany([
    { email: 'a@test.com', password: 's', role: 'user' },
    { email: 'b@test.com', password: 's', role: 'user' },
  ])

  await client.post('/admin/promote-all')

  // 仅当恰好有 2 行匹配时通过
  await db.assertHas('users', { role: 'admin' }, 2)
})

断言行缺失

assertMissing 方法是 assertHas 的逆操作。它验证表中没有任何行与给定的数据匹配。

tests/functional/users.spec.ts
test('deletes inactive users', async ({ client, db }) => {
  await User.create({ email: 'old@test.com', password: 's', active: false })

  await client.post('/admin/cleanup')

  await db.assertMissing('users', { active: false })
})

断言行数

assertCount 方法检查表中的总行数,而不管其内容如何。

tests/functional/users.spec.ts
test('seeds default users', async ({ client, db }) => {
  await client.post('/setup/seed')

  await db.assertCount('users', 5)
})

assertEmpty 方法是 assertCount(table, 0) 的简写形式。它验证一个表完全没有行。

tests/functional/tokens.spec.ts
test('clears all expired tokens', async ({ client, db }) => {
  await client.post('/admin/clear-tokens')

  await db.assertEmpty('auth_access_tokens')
})

断言模型存在

在使用 Lucid 模型时,你可以直接对模型实例进行断言,而不必编写表级别的查询。assertModelExists 方法检查模型的 primary key 是否仍然存在于数据库中。

tests/functional/users.spec.ts
import User from '#models/user'

test('creates a user record', async ({ client, db }) => {
  await client.post('/register').json({
    email: 'jul@test.com',
    password: 'secret123',
  })

  const user = await User.findByOrFail('email', 'jul@test.com')
  await db.assertModelExists(user)
})

assertModelMissing 方法验证模型实例不再存在于数据库中。这对于测试删除操作很有用。

tests/functional/users.spec.ts
test('deletes a user', async ({ client, db }) => {
  const user = await User.create({
    email: 'jul@test.com',
    password: 'secret123',
  })

  await client.delete(`/users/${user.id}`)

  await db.assertModelMissing(user)
})

断言参考

MethodDescription
assertHas(table, data, count?)验证与 data 匹配的行存在。当提供 count 时,检查匹配的精确数量。
assertMissing(table, data)验证没有行与 data 匹配。
assertCount(table, count)验证表恰好拥有 count 总行数。
assertEmpty(table)验证表没有行。assertCount(table, 0) 的简写形式。
assertModelExists(model)通过 primary key 验证模型实例存在于数据库中。
assertModelMissing(model)验证模型实例不存在于数据库中。