「数据库」没经过这些测试,你的微服务架构也敢进入生产环境?( 二 )


「数据库」没经过这些测试,你的微服务架构也敢进入生产环境?
本文插图

「数据库」没经过这些测试,你的微服务架构也敢进入生产环境?
本文插图

单元测试 所谓单元 , 是指应用程序当中的最小可测试部分 , 例如函数、类或者过程 。 单元测试则代表一种软件测试方法 , 旨在测试源代码中的各个单元 , 以确定其是否符合开发阶段的预期设计 。
编写单元测试 , 是为了保证不同代码形式(函数、类等)的每个简单实现 , 均符合设计、要求并能够按预期运行 。
单元测试的目标 , 在于隔离程序中的各个部分 , 并测试这些部分是否正常工作 。
换言之 , 与当前测试单元无关的其他代码部分 , 则以模拟形式存在 , 仅作为运行环境使用 。
在我们的示例中 , 需要测试的单元自然就是之前提到的 createUser 了 。 这意味着我们首先得把它跟其他组件隔离开来 。 因此 , 第一步就是模拟 user repository 类 , 这个类代表着数据库使用 TypeORM 时的链接 。
如果分析服务中的 createUser 函数 , 就会发现它的作用只是对密码进行哈希处理 , 而后将 User 对象保存在数据库内 。 以此为基础 , 我们编写出以下测试套件:
「数据库」没经过这些测试,你的微服务架构也敢进入生产环境?
本文插图

首先 , 我们编写一个 beforeAll 函数来创建测试模块 。 接下来 , 使用模拟类替换原始 repository , 该模拟类将仅返回需要保存在数据库中的对象 。
在这个函数中 , 我们还得考虑这样一种极端要求:
使用特定属性(邮件、密码等)创建一个新用户对象 , 请确保密码经过哈希处理
这里 , 我们会模拟 save() 函数 , 因为它来自 TypeORM、不属于测试中的对象单元范畴 , 使用简单函数将其覆盖以返回我们传递的对象 。
到这里 , 我们的工作就很简单了:检查在发送对象过程中使用的邮件属性与哈希密码是否正确 。
集成测试 集成测试属于另一种软件测试方法 , 用于验证源代码单元内的组成功能是否正常 。
单元测试的目标是保证代码符合其设计与功能要求 , 同时能够按照预期方式运行 。 集成测试则更进一步 , 将不同模块融合在一起 , 并测试它们是否能够正确交互 。
在本示例中 , 我们将 UserModule 与 TypeORM 模块(存在依赖关系)结合起来 , 检查新用户是否被正确保存在数据库内 。
这一次 , 我们仍然需要使用之前提到的函数 , 只是具体测试流程有所区别:
「数据库」没经过这些测试,你的微服务架构也敢进入生产环境?
本文插图

这一次 , beforeAll 函数不再模拟 userRepository , 而直接使用原始库;此外 , 我们还添加 databaseModule 以创建指向数据库的连接 。
与此同时 , 由于我们现在使用的是真实数据库 , 因此必须编写对应函数调整数据库以完成测试 。
在测试之前与之后 , 我们需要清空数据库 , 保证不存在任何干扰内容 。
另外 , 我们还需要手动关闭指向数据库的连接 , 这样才能保证测试完成后所有处理程序都被正确关闭 。
通过单元测试 , 我们已经检查了函数能否正常工作 。 因此 , 这里可以直接测试该函数能够与 TypeORM 的 save() 方法相结合 , 进而将新用户对象存储在数据库内 。
我们编写了名为 getOneUserFromDb 的辅助函数 , 它的作用顾名思义——从数据库内获取一个用户 。 接下来 , 检查邮件与 accountConfimed 属性是否正确(后者在实体类内应默认设置为 false) 。
端到端测试 端到端测试是一种软件测试方法 , 旨在持续跟踪应用程序的整个运行流程是否与设计思路一致 。
这类测试的目标 , 在于确保应用程序能否在真实场景下按预期方式运行 。


推荐阅读