在过去的几个月里,我正在开发一个从头开始的大项目的后端(REST API)。我们遵循BDD(行为驱动开发)标准,所以现在我们有大量的测试(~1000)。测试是使用chai编写的 - 一个用于Node.JS的BDD框架,但我认为这个问题可以在编写测试时扩展为一般的良好实践。
首先,我们尝试尽可能避免代码冗余,并且进展顺利。随着代码行和项目工作人员数量的增加,它变得越来越混乱,但可读性更强。有时在15分钟内可以应用的代码中的微小变化导致需要改变例如30多个文件中的模拟数据和方法等,这意味着6小时的更改和运行测试(极端的例子)。
TL:DR
我们现在要重构这些BDD测试。作为一个例子,我们有这样一个功能:
function RegisterUserAndGetJWTToken(user_data, next: any){
chai.request(server).post(REGISTER_URL).send(user_data).end((err: any, res: any) => {
token = res.body.token;
next(token);
})
}
此功能在我们的大多数测试文件中使用。创建像test-suite
这样的包含这种函数的东西是否有意义,或者在编写测试时是否有更好的方法来避免冗余?然后我们可以使用这样的导入:
import {RegisterUserAndGetJWTToken} from "./test-suite";
import {user_data} from "./test-mock-data";
inject
或inherit
test-suite
的方法
每个文件,以避免导入并默认在每个文件中使用它?提前致谢!
答案 0 :(得分:1)
您的原则应该是提高测试本身的抽象级别。这意味着测试应该包含以域语言表示的高级方法调用。例如:
registerUser('John', 'john@smith.com')
lastEmail = getLastEmailSent()
lastEmail.receipient.should.be 'john@smith.com'
lastEmail.contents.should.contain 'Dear John'
现在在实施这些方法时,可能会发生很多事情。特别是,registerUser
函数可以执行发布请求(如您的示例中所示)。 getLastEmailSent
可以从邮件队列或虚假SMTP服务器中读取。问题是你隐藏了API背后的细节。
如果您遵循这一原则,您最终会创建一个自动化层 - 一个面向域的程序化API到您的系统。创建此图层时,您遵循所有良好的设计原则,例如DRY。
好处是,当代码发生变化时,测试代码中只有一个地方需要改变 - 在自动化层中,而不是在测试本身。
我看到你提出的建议(提取RegisterUserAndGetJWTToken
和测试数据)是创建自动化层的一个很好的步骤。我不会担心require
电话。我没有看到任何理由不明确我们的测试取决于什么。也许在稍后阶段,其中一些可以收集在更大的模块中(registration
,emailing
等。)
在适当的级别自动化。
有时通过UI或REST会更好,但通常直接调用函数会更明智。例如,如果您编写一个用于计算发票上的税金的测试,则对每个测试用例进行整个应用程序测试将是一种过度杀伤力。离开一个端到端测试看看所有部分是否一起工作,并在尽可能低的级别自动化所有特定情况,这样会好得多。这样我们就可以获得良好的覆盖范围,以及测试套件的速度和稳健性。
编写测试时的指导原则是可读性。
您可以参考this discussion获得一个很好的解释。
在处理生产代码时,请小心处理您的测试助手代码/自动化层。
这意味着您应该遵循所有良好的设计原则,非常谨慎地重构它。