在 NestJS 中对具有许多依赖项的服务进行单元测试
Unit testing a service with many dependencies in NestJS
在 Nest 中构建 API 时,我经常遇到一个问题,即特定 API 可能需要使用多个 Nest 模块来完成它的工作。我想知道是否有更好的方法来构建我的模块,以便更容易地对它们进行单元测试。
例如,假设我们有一个 OrderService
。 OrderService
使用一些不同的依赖项来完成它的工作:
- 它使用
ProductsService
来查找产品详细信息和价格。
- 它使用
UsersService
来查找客户信息,例如 Stripe 客户 ID。
- 它使用 Typeorm 来处理将
Order
写入数据库
- 最后,假设它使用
CouponsService
来查找和验证 Order
的优惠券详细信息。
为了这个例子,让我们假设这 4 个依赖项中的每一个都是它自己的 Nest 模块。
在对 OrdersService
进行单元测试时,我需要剔除 4 个不同的依赖项。这似乎比应该做的要多得多,所以我意识到必须有更好的方法。
我尝试做的一件事是创建单独的帮助程序文件来设置每个服务模拟。这减少了使用特定依赖项的每个服务的样板数量,但您最终仍然会遇到 1 个服务可能具有 4 个不同依赖项的情况。
理想情况下,我想实现一些模式或结构,这样当我测试一个文件时,依赖关系要么非常简单,要么自动模拟,或者一个特定文件一次只有 1 个依赖关系,而不会过度简化系统。
我的问题归结为:
你如何在一个服务中处理许多像这样的依赖关系,而不至于最终导致测试一个函数需要你模拟 4 个以上的方法。我很想听听 Nest 特定的方法来做到这一点,但我也很感激任何通用的软件工程示例或模式来研究。
There's a pull request to allow for auto-mocking with Nest's @nestjs/testing
package,但它还没有被接受(虽然正在努力!),并且有一个名为 @golevelup/ts-jest
的包允许您非常快速地设置对象的模拟并且容易地。因此,不必定义整个 { get: jest.fn(), create: jest.fn(), ...etc }
useValue
提供程序,您可以像
const modFixture = await Test.createTestingModule({
providers: [
OrderService,
{
provide: ProductService,
useValue: createMock<ProductService>(),
},
{
provide: UserService,
useValue: createMock<UserService>(),
},
...etc
]
}).compile();
并且所有方法都将设置为jest.fn()
方法,可以根据您的特定测试进行扩展
在 Nest 中构建 API 时,我经常遇到一个问题,即特定 API 可能需要使用多个 Nest 模块来完成它的工作。我想知道是否有更好的方法来构建我的模块,以便更容易地对它们进行单元测试。
例如,假设我们有一个 OrderService
。 OrderService
使用一些不同的依赖项来完成它的工作:
- 它使用
ProductsService
来查找产品详细信息和价格。 - 它使用
UsersService
来查找客户信息,例如 Stripe 客户 ID。 - 它使用 Typeorm 来处理将
Order
写入数据库 - 最后,假设它使用
CouponsService
来查找和验证Order
的优惠券详细信息。
为了这个例子,让我们假设这 4 个依赖项中的每一个都是它自己的 Nest 模块。
在对 OrdersService
进行单元测试时,我需要剔除 4 个不同的依赖项。这似乎比应该做的要多得多,所以我意识到必须有更好的方法。
我尝试做的一件事是创建单独的帮助程序文件来设置每个服务模拟。这减少了使用特定依赖项的每个服务的样板数量,但您最终仍然会遇到 1 个服务可能具有 4 个不同依赖项的情况。
理想情况下,我想实现一些模式或结构,这样当我测试一个文件时,依赖关系要么非常简单,要么自动模拟,或者一个特定文件一次只有 1 个依赖关系,而不会过度简化系统。
我的问题归结为:
你如何在一个服务中处理许多像这样的依赖关系,而不至于最终导致测试一个函数需要你模拟 4 个以上的方法。我很想听听 Nest 特定的方法来做到这一点,但我也很感激任何通用的软件工程示例或模式来研究。
There's a pull request to allow for auto-mocking with Nest's @nestjs/testing
package,但它还没有被接受(虽然正在努力!),并且有一个名为 @golevelup/ts-jest
的包允许您非常快速地设置对象的模拟并且容易地。因此,不必定义整个 { get: jest.fn(), create: jest.fn(), ...etc }
useValue
提供程序,您可以像
const modFixture = await Test.createTestingModule({
providers: [
OrderService,
{
provide: ProductService,
useValue: createMock<ProductService>(),
},
{
provide: UserService,
useValue: createMock<UserService>(),
},
...etc
]
}).compile();
并且所有方法都将设置为jest.fn()
方法,可以根据您的特定测试进行扩展