e2e 如何与 guard nestjs

Posted

技术标签:

【中文标题】e2e 如何与 guard nestjs【英文标题】:How e2e with guard nestjs 【发布时间】:2020-02-10 01:16:59 【问题描述】:

我想使用nestjs 对一个名为/users 的端点进行e2e,但出现错误。我对如何让警卫通过测试感到疑惑。

第一个错误

Nest 无法解析 UserModel (?) 的依赖关系。请确保 索引 [0] 处的参数 DatabaseConnection 在 MongooseModule 上下文。

第二个错误

预期 200“OK”,得到 401“Unauthorized”

App.module

@Module(
  imports: [
    MongooseModule.forRootAsync(
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => (
        uri: configService.mongoUri,
        useNewUrlParser: true,
      ),
      inject: [ConfigService],
    ),
    GlobalModule,
    UsersModule,
    AuthModule,
    PetsModule,
    RestaurantsModule,
    ConfigModule,
  ],
  controllers: [],
  providers: [],
)
export class AppModule implements NestModule 
  configure(consumer: MiddlewareConsumer) 
    consumer
      .apply(TokenDataMiddleware)
      .forRoutes( path: '*', method: RequestMethod.ALL );
  

用户服务

@Injectable()
export class UsersService 
  constructor(
    @InjectModel('User') private readonly userModel: Model<UserDocument>,
    private readonly utilsService: UtilsService,
    private readonly configService: ConfigService,
  )  
async getAllUsers(): Promise<UserDocument[]> 
    const users = this.userModel.find().lean().exec();
    return users;
  

控制器

@Controller('users')
export class UsersController 
    constructor(private readonly usersService: UsersService, private readonly utilsService: UtilsService)  
    @Get()
    @ApiBearerAuth()
    @UseGuards(JwtAuthGuard)
    async users() 
        const users = await this.usersService.getAllUsers();
        return users;
    

e2e 文件

describe('UsersController (e2e)', () => 
  let app: INestApplication;
  beforeAll(async () => 
    const testAppModule: TestingModule = await Test.createTestingModule(
      imports: [AppModule, GlobalModule,
        UsersModule,
        AuthModule,
        PetsModule,
        RestaurantsModule,
        ConfigModule],
      providers: [],
    ).compile();

    app = testAppModule.createNestApplication();
    await app.init();
  );

  it('GET all users from API', async () => 
    // just mocked users;
    const users = getAllUsersMock.buildList(2);
    const response = await request(app.getHttpServer())
      .get('/users')
      .expect(200);
  );

  afterAll(async () => 
    await app.close();
  );
);

【问题讨论】:

【参考方案1】:

在单元测试中,您测试单个单元(服务、控制器等),这意味着您导入一个单元并模拟其所有依赖项。然而,在 e2e 测试中,您想要测试您的整个应用程序,因此您应该导入根模块 (AppModule) 而不是单个单元或模块。有时您可能想要模拟应用程序的特定部分,例如数据库或第 3 方 API;你可以用overrideProvider 等来做到这一点。

在您的情况下,您可能缺少从您的AppModule 导入的MongooseModuleforRoot。导入 AppModule,而不是重组应用程序的某些部分:

await Test.createTestingModule(
      imports: [AppModule],
    ).compile()
      .overrideProvider(HttpService)
      .useValue(httpServiceMock);

如果您的 API 受到保护,您需要对其进行身份验证。您可以通过编程方式创建 JWT,也可以使用您的 API。我假设您在以下示例中有一个用于身份验证的端点:

const loginResponse = await request(app.getHttpServer())
  .post('/auth/login')
  .send( username: 'user', password: '123456' )
  .expect(201);
// store the jwt token for the next request
const  jwt  = loginResponse.body;

await request(app.getHttpServer())
  .get('/users')
  // use the jwt to authenticate your request
  .set('Authorization', 'Bearer ' + jwt)
  .expect(200)
  .expect(res => expect(res.body.users[0])
    .toMatchObject( username: 'user' ));

【讨论】:

您好,感谢您的回答,我用您的更改更新了问题(它有效),但保留我关于模拟 jwt 令牌的问题以通过 JwtAuthGuard。谢谢! @anthonywillismuñoz 查看我的编辑。由于您的 API 受到保护,因此 401 错误符合预期。测试未经身份验证的请求无法访问您的 API 实际上很好。要测试受保护的资源,您必须设置 Authorization 标头,请参见示例。此外,您不需要导入所有模块。 导入 AppModule。它本身将导入所有其他模块。 @Kim Kern 什么是 httpServiceMock?我遇到了同样的问题,无法理解 @MegaRoks 看看这个关于如何创建模拟的线程:***.com/a/55366343/4694994

以上是关于e2e 如何与 guard nestjs的主要内容,如果未能解决你的问题,请参考以下文章

NestJS:如何在从 JWT AuthGuard 扩展的 GraphQL 自定义 Guard 中从请求中获取用户

如何使用 NestJS 和 class-validator 手动测试输入验证

用 jest @nestjs 运行 e2e 测试

NestJS:如何在 canActivate 中模拟 ExecutionContext

Guard 不在 NestJs 中执行护照策略

NestJS - 从 Guard 访问用户