如何为下述控制器创建测试?是否需要为该接口代码编写测试用例
是否需要为该接口编写测试?
必须写。这个接口是用户信息更新的核心入口,直接关联三个高风险出问题的环节:
- 代码硬编码从
req.user.user路径提取当前登录用户信息,一旦鉴权中间件返回的用户字段结构调整,接口会直接抛出500错误 - 接口涉及用户身份权限逻辑,必须保证不会被恶意构造请求绕过,出现越权修改他人信息的问题
- 控制器作为请求入口,要保证请求体参数、上下文用户信息正确透传给服务层,同时把服务层返回结果正确返回给调用方,不能出现参数错传、返回值篡改的问题
如何为该控制器创建测试用例
这是典型的NestJS框架控制器代码,推荐用Jest做单元测试,通过mock隔离依赖的UserService层,只校验控制器本身的逻辑,不需要连接数据库、启动完整服务,服务层的业务逻辑单独在UserService的测试里覆盖即可。
必覆盖测试场景
- 正常流程场景:构造合法的
UpdateUserDto参数、携带正确登录用户信息的请求对象,调用控制器方法,校验两点:一是userService.update被调用时的入参完全正确,第一个参数是req.user.user对应的登录用户信息,第二个参数是传入的DTO对象;二是控制器返回值和Service层返回的结果完全一致 - 鉴权异常场景:构造缺少
req.user.user字段的请求对象(对应鉴权失效、登录态过期的情况),校验控制器会抛出预期错误 - 参数校验场景:构造不符合
UpdateUserDto校验规则的请求体(比如字段类型错误、必填字段缺失、字段长度超出限制),校验请求会被参数校验层拦截返回对应错误(这个场景如果全局校验管道是统一配置的,也可以放到e2e测试里覆盖) - 越权风险校验:确认控制器逻辑没有从请求体中读取用户ID/用户标识覆盖
req.user.user的取值,从入口层堵死越权修改的可能
测试代码参考
import { Test, TestingModule } from '@nestjs/testing'; import { UserController } from './user.controller'; import { UserService } from './user.service'; import { UpdateUserDto } from './dto/update-user.dto'; describe('UserController', () => { let controller: UserController; let mockUserService: { update: jest.Mock }; beforeEach(async () => { // 模拟依赖的UserService,隔离真实业务逻辑 mockUserService = { update: jest.fn() }; const moduleRef: TestingModule = await Test.createTestingModule({ controllers: [UserController], providers: [ { provide: UserService, useValue: mockUserService } ] }).compile(); controller = moduleRef.get<UserController>(UserController); }); test('正常请求时应正确透传参数并返回Service层结果', async () => { const testUpdateDto: UpdateUserDto = { nickname: '测试昵称', avatar: 'test-avatar-path' }; const testReq = { user: { user: { id: 1001, username: 'test_account' } } }; const mockServiceReturn = { id: 1001, username: 'test_account', nickname: '测试昵称', avatar: 'test-avatar-path' }; mockUserService.update.mockResolvedValue(mockServiceReturn); const result = await controller.update(testUpdateDto, testReq); // 校验Service调用参数正确 expect(mockUserService.update).toHaveBeenCalledTimes(1); expect(mockUserService.update).toHaveBeenCalledWith(testReq.user.user, testUpdateDto); // 校验返回值正确 expect(result).toEqual(mockServiceReturn); }); test('请求上下文缺少登录用户信息时应抛出错误', async () => { const testUpdateDto: UpdateUserDto = { nickname: '测试昵称' }; const invalidReq = { user: {} }; // 模拟鉴权中间件未正确注入用户信息的情况 await expect(controller.update(testUpdateDto, invalidReq)).rejects.toThrow(); }); });
如果需要做接口级别的端到端测试,可以搭配supertest发送真实HTTP请求,携带合法/非法的鉴权令牌、构造不同的请求体,校验接口的HTTP状态码、返回结构是否符合预期,这类测试不需要关心控制器和服务的内部调用逻辑,只校验接口对外的表现。
内容的提问来源于stack exchange,提问作者Hossein Agharezaei
相关产品推荐
相关产品推荐

