Typescript NestJS体系结构与测试

Typescript NestJS体系结构与测试,typescript,unit-testing,nestjs,Typescript,Unit Testing,Nestjs,我目前正在使用NestJS进行一个项目,当涉及到测试时,我认为架构有点麻烦。据我所知,推荐的方法有两层:控制器和服务 控制器 控制器在需要时很容易测试,尽管我不理解测试模块的必要性(服务也是如此): const module=wait Test.createTestingModule({ 控制器:[MyController] 提供者:[MyService]//jest.mock用于模拟MyService }).compile(); 控制器=模块.get(MyController) 直接注入我需

我目前正在使用NestJS进行一个项目,当涉及到测试时,我认为架构有点麻烦。据我所知,推荐的方法有两层:控制器和服务

控制器 控制器在需要时很容易测试,尽管我不理解测试模块的必要性(服务也是如此):

const module=wait Test.createTestingModule({
控制器:[MyController]
提供者:[MyService]//jest.mock用于模拟MyService
}).compile();
控制器=模块.get(MyController)
直接注入我需要的任何模拟似乎都相当容易:

controller=new MyController(new MyService())//再次使用jest.mock来模拟MyService
对我来说,后一个例子更短,更容易理解,并且准确地表达了我想要测试的内容。它不测试依赖注入是否有效,但(至少在我们的应用程序中)在启动时由NestJS检查

服务 当涉及到测试服务时,我发现自己在大量模仿存储库

const-spy=jest.spyOn(存储库'save')
.mockReturnValueOnce(null)//类似于应该在何时引入jest
等待服务。创建('Stackoverflow问题','我不明白…'))
expect(spy.mock.calls[0][0]).toEqual({
标题:“Stackoverflow问题”,
内容:“我不明白……”,
注释:[]//没有初始注释
})
我找到的每个教程/示例都建议将存储库放入服务中。我曾考虑过将它放在控制器(或GraphQL的解析器)中,但它感觉不到正确的职责分离,并且在使用Rest和GraphQL时会导致代码重复。对我来说,最好的方法似乎是创建另一个层(或向实体类添加函数),然后负责域/业务逻辑。这很容易测试(没有模拟和承诺)

const question=Domain.create('Stackoverflow上的问题','I not get it…'))
//或const question=question.create('Stackoverflow上的问题','I not get it…'))
期待(问题)。托夸尔({
标题:“Stackoverflow问题”,
内容:“我不明白……”,
注释:[]//没有初始注释
})
然后服务将只负责I/O,这似乎是一个很大的关注点分离

我现在的问题是:这对NestJS有意义吗?看来这不是建议的方法。也许我遗漏了一些重要的东西,或者可能我使架构变得更加复杂

提前感谢您的投入

安德烈亚斯

做类似事情的能力

const myController=new MyConstroller(new MyService());
从理论上讲,这是很好的,但一旦您的服务开始依赖于其他服务(Redis、TypeORM、应用程序中的其他服务),它很快就会变得难以使用

const myController=新的myController(
新MyService(
新的再贴现服务(再贴现选项),
新MyEntityReposiotry(MyEntityReposioptions),
新的其他服务(新的再贴现服务(再贴现))
)
);
确保在创建控制器之前可以将这些设置为变量,这样可以减少实例化类的次数,但仍然需要自己进行大量注入

有了Nest架构和测试类,您可以像

beforeach(异步()=>{
const module=await Test.createTestingModule({
控制器:[MyController],
供应商:[
{
提供:MyService,
useValue:myServiceMock
}
],
}).compile();
});
现在您可以很容易地获得对“我的服务”的mock的引用,您可以定义服务函数的一般结构和默认返回值,并且仍然可以使用
module.get(MyService | MyController)
获得对服务和控制器类的引用

当然,您可以始终使用
jest.mock()
启动一个基本存根并模拟您认为合适的返回值,但请记住这会如何影响测试的外观。NestJS的一个优点是它固执己见,并且有自己喜欢的外观


如果您想看到示例,可以看到不同类型项目的大量测试样本,包括rxjs、typeorm和graphql。

执行以下操作的能力

const myController=new MyConstroller(new MyService());
从理论上讲,这是很好的,但一旦您的服务开始依赖于其他服务(Redis、TypeORM、应用程序中的其他服务),它很快就会变得难以使用

const myController=新的myController(
新MyService(
新的再贴现服务(再贴现选项),
新MyEntityReposiotry(MyEntityReposioptions),
新的其他服务(新的再贴现服务(再贴现))
)
);
确保在创建控制器之前可以将这些设置为变量,这样可以减少实例化类的次数,但仍然需要自己进行大量注入

有了Nest架构和测试类,您可以像

beforeach(异步()=>{
const module=await Test.createTestingModule({
控制器:[MyController],
供应商:[
{
提供:MyService,
useValue:myServiceMock
}
],
}).compile();
});
现在您可以很容易地获得对“我的服务”的mock的引用,您可以定义服务函数的一般结构和默认返回值,并且仍然可以使用
module.get(MyService | MyController)
获得对服务和控制器类的引用

当然,您可以始终使用
jest.mock()
启动一个基本存根并模拟您认为合适的返回值,但请记住这会如何影响测试的外观。NestJS的一个绘图