控制台测试
命令行测试是指测试作为应用程序或包代码库一部分的自定义 Ace 命令。
在本指南中,我们将学习如何为命令编写测试、模拟日志记录器输出以及捕获 CLI 提示。
基本示例
让我们首先创建一个名为 greet 的新命令。
node ace make:command greetimport { BaseCommand } from '@adonisjs/core/ace'
import { CommandOptions } from '@adonisjs/core/types/ace'
export default class Greet extends BaseCommand {
static commandName = 'greet'
static description = '通过名称问候用户名'
static options: CommandOptions = {}
async run() {
this.logger.info('来自 "Greet" 的 Hello world')
}
}让我们在 tests/unit 目录中创建一个单元测试。如果尚未定义,请随时定义单元测试套件。
node ace make:test commands/greet --suite=unit
# DONE: create tests/unit/commands/greet.spec.ts让我们打开新创建的文件并编写以下测试。我们将使用 ace 服务创建 Greet 命令的实例,并断言它成功退出。
import { test } from '@japa/runner'
import Greet from '#commands/greet'
import ace from '@adonisjs/core/services/ace'
test.group('Commands greet', () => {
test('应该问候用户并以退出码 0 完成', async () => {
/**
* 创建 Greet 命令类的实例
*/
const command = await ace.create(Greet, [])
/**
* 执行命令
*/
await command.exec()
/**
* 断言命令以状态码 0 退出
*/
command.assertSucceeded()
})
})让我们使用以下 ace 命令运行测试。
node ace test --files=commands/greet测试日志记录器输出
Greet 命令当前将日志消息写入终端。要捕获此消息并为其编写断言,我们需要将 ace 的 UI 库切换到 raw 模式。
在 raw 模式下,ace 不会将任何日志写入终端。相反,将它们保存在内存中以编写断言。
我们将使用 Japa each.setup 钩子来切换进出 raw 模式。
test.group('Commands greet', (group) => {
// highlight-start
group.each.setup(() => {
ace.ui.switchMode('raw')
return () => ace.ui.switchMode('normal')
})
// highlight-end
// 测试在这里
})定义钩子后,您可以按如下方式更新测试。
test('应该问候用户并以退出码 1 完成', async () => {
/**
* 创建 Greet 命令类的实例
*/
const command = await ace.create(Greet, [])
/**
* 执行命令
*/
await command.exec()
/**
* 断言命令以状态码 0 退出
*/
command.assertSucceeded()
// highlight-start
/**
* 断言命令打印了以下日志消息
*/
command.assertLog('[ blue(info) ] 来自 "Greet" 的 Hello world')
// highlight-end
})测试表格输出
与测试日志消息类似,您可以通过将 UI 库切换到 raw 模式来为表格输出编写断言。
async run() {
const table = this.ui.table()
table.head(['Name', 'Email'])
table.row(['Harminder Virk', 'virk@adonisjs.com'])
table.row(['Romain Lanz', 'romain@adonisjs.com'])
table.row(['Julien-R44', 'julien@adonisjs.com'])
table.row(['Michaël Zasso', 'targos@adonisjs.com'])
table.render()
}给定上述表格,您可以如下为其编写断言。
const command = await ace.create(Greet, [])
await command.exec()
command.assertTableRows([
['Harminder Virk', 'virk@adonisjs.com'],
['Romain Lanz', 'romain@adonisjs.com'],
['Julien-R44', 'julien@adonisjs.com'],
['Michaël Zasso', 'targos@adonisjs.com'],
])捕获提示
由于提示会阻塞终端等待手动输入,因此在编写测试时必须以编程方式捕获和响应它们。
提示使用 prompt.trap 方法捕获。该方法接受提示标题(区分大小写)并提供可链式 API 来配置其他行为。
提示触发后陷阱会自动移除。如果测试完成时未触发带有陷阱的提示,将抛出错误。
在以下示例中,我们在标题为 "你叫什么名字?" 的提示上放置陷阱,并使用 replyWith 方法回答它。
const command = await ace.create(Greet, [])
// highlight-start
command.prompt
.trap('你叫什么名字?')
.replyWith('Virk')
// highlight-end
await command.exec()
command.assertSucceeded()选择选项
您可以使用 chooseOption 和 chooseOptions 方法使用 select 或 multi-select 提示选择选项。
command.prompt
.trap('选择包管理器')
.chooseOption(0)command.prompt
.trap('选择数据库管理器')
.chooseOptions([1, 2])接受或拒绝确认提示
您可以接受或拒绝使用 toggle 和 confirm 方法显示的提示。
command.prompt
.trap('要删除所有文件吗?')
.accept()command.prompt
.trap('要删除所有文件吗?')
.reject()断言验证
要测试提示的验证行为,您可以使用 assertPasses 和 assertFails 方法。这些方法接受提示的值,并根据提示的 validate 方法测试它。
command.prompt
.trap('你叫什么名字?')
// 断言当提供空值时提示失败
.assertFails('', '请输入您的名字')
command.prompt
.trap('你叫什么名字?')
.assertPasses('Virk')以下是同时使用断言和回复提示的示例。
command.prompt
.trap('你叫什么名字?')
.assertFails('', '请输入您的名字')
.assertPasses('Virk')
.replyWith('Romain')可用断言
以下是命令实例上可用的断言方法列表。
assertSucceeded
断言命令以 exitCode=0 退出。
await command.exec()
command.assertSucceeded()assertFailed
断言命令以非零 exitCode 退出。
await command.exec()
command.assertFailed()assertExitCode
断言命令以特定的 exitCode 退出。
await command.exec()
command.assertExitCode(2)assertNotExitCode
断言命令以任何 exitCode 退出,但不是给定的退出码。
await command.exec()
command.assertNotExitCode(0)assertLog
断言命令使用 this.logger 属性写入日志消息。您可以选择将输出流断言为 stdout 或 stderr。
await command.exec()
command.assertLog('来自 "Greet" 的 Hello world')
command.assertLog('来自 "Greet" 的 Hello world', 'stdout')assertLogMatches
断言命令写入与给定正则表达式匹配的日志消息。
await command.exec()
command.assertLogMatches(/Hello world/)assertTableRows
断言命令向 stdout 打印表格。您可以将表格行作为列数组提供。列表示为单元格数组。
await command.exec()
command.assertTableRows([
['Harminder Virk', 'virk@adonisjs.com'],
['Romain Lanz', 'romain@adonisjs.com'],
['Julien-R44', 'julien@adonisjs.com'],
])