4

我正在尝试对这个控制器进行单元测试并模拟它需要的服务/存储库。

@Controller('auth')
export class AuthController {
    constructor(
        private readonly authService: AuthService,
        private readonly usersService: UsersService,
    ) {}

    @Post('register')
    public async registerAsync(@Body() createUserModel: CreateUserModel) {
        const result = await this.authenticationService.registerUserAsync(createUserModel);

        // more code here
    }

    @Post('login')
    public async loginAsync(@Body() login: LoginModel): Promise<{ accessToken: string }> {
        const user = await this.usersService.getUserByUsernameAsync(login.username);

        // more code here
    }
}

这是我的单元测试文件:

describe('AuthController', () => {
    let authController: AuthController;
    let authService: AuthService;

    beforeEach(async () => {
        const moduleRef: TestingModule = await Test.createTestingModule({
            imports: [JwtModule],
            controllers: [AuthController],
            providers: [
                AuthService,
                UsersService,
                {
                    provide: getRepositoryToken(User),
                    useClass: Repository,
                },
            ],
        }).compile();

        authController = moduleRef.get<AuthenticationController>(AuthenticationController);
        authService = moduleRef.get<AuthenticationService>(AuthenticationService);
    });

    describe('registerAsync', () => {
        it('Returns registration status when user registration succeeds', async () => {
            let createUserModel: CreateUserModel = {...}

            let registrationStatus: RegistrationStatus = {
                success: true,
                message: 'User registered successfully',
            };

            jest.spyOn(authService, 'registerUserAsync').mockImplementation(() =>
                Promise.resolve(registrationStatus),
            );

            expect(await authController.registerAsync(createUserModel)).toEqual(registrationStatus);
        });
    });
});

但是在运行它时,我收到以下错误:

  ● AuthController › registerAsync › Returns registration status when user registration succeeds

    Nest can't resolve dependencies of the JwtService (?). Please make sure that the argument JWT_MODULE_OPTIONS at index [0] is available in the JwtModule context.

    Potential solutions:
    - If JWT_MODULE_OPTIONS is a provider, is it part of the current JwtModule?
    - If JWT_MODULE_OPTIONS is exported from a separate @Module, is that module imported within JwtModule?
      @Module({
        imports: [ /* the Module containing JWT_MODULE_OPTIONS */ ]
      })

      at Injector.lookupComponentInParentModules (../node_modules/@nestjs/core/injector/injector.js:191:19)
      at Injector.resolveComponentInstance (../node_modules/@nestjs/core/injector/injector.js:147:33)
      at resolveParam (../node_modules/@nestjs/core/injector/injector.js:101:38)
          at async Promise.all (index 0)
      at Injector.resolveConstructorParams (../node_modules/@nestjs/core/injector/injector.js:116:27)
      at Injector.loadInstance (../node_modules/@nestjs/core/injector/injector.js:80:9)
      at Injector.loadProvider (../node_modules/@nestjs/core/injector/injector.js:37:9)
      at Injector.lookupComponentInImports (../node_modules/@nestjs/core/injector/injector.js:223:17)
      at Injector.lookupComponentInParentModules (../node_modules/@nestjs/core/injector/injector.js:189:33)

  ● AuthController › registerAsync › Returns registration status when user registration succeeds

    Cannot spyOn on a primitive value; undefined given

      48 |             };
      49 |
    > 50 |             jest.spyOn(authService, 'registerUserAsync').mockImplementation(() =>
         |                  ^
      51 |                 Promise.resolve(registrationStatus),
      52 |             );
      53 |

      at ModuleMockerClass.spyOn (../node_modules/jest-mock/build/index.js:780:13)
      at Object.<anonymous> (Authentication/authentication.controller.spec.ts:50:18)

我不太确定如何进行,所以我需要一些帮助。

4

3 回答 3

2

我在这里注意到一些事情:

  1. 如果您正在测试控制器,则不需要模拟超过一层的深度 pf 服务

  2. 您几乎不应该imports在单元测试中遇到需要数组的用例。

您可以为您的测试用例做的事情类似于以下内容:

beforeEach(async () => {
  const modRef = await Test.createTestingModule({
    controllers: [AuthController],
    providers: [
      {
        provide: AuthService,
        useValue: {
          registerUserAsync: jest.fn(),
        }

      },
      {
        provide: UserService,
        useValue: {
          getUserByUsernameAsync: jest.fn(),
        }
      }
    ]
  }).compile();
});

现在您可以使用 auth 服务和用户服务modRef.get()并将它们保存到一个变量中,以便稍后向它们添加模拟。您可以查看此测试存储库,其中包含许多其他示例。

于 2020-07-10T15:55:43.873 回答
1

如果您正在为 NestJS 构建一个完整的集成测试套件,那么如果您导入一个module导入AuthService. 这将不可避免地需要JwtServicewhich 将出错:Nest can't resolve dependencies of the JwtService (?). Please make sure that the argument JWT_MODULE_OPTIONS at index [0] is available in the RootTestModule context.

这是我解决这个问题的方法。我补充说:

                JwtModule.registerAsync({
                    imports: [ConfigModule],
                    inject: [ConfigService],
                    useFactory: async (configService: ConfigService) => ({
                        secret: configService.get('JWT_SECRET'),
                        signOptions: { expiresIn: '1d' }
                    })
                }),

在我的通话中我的imports: []功能await Test.createTestingModule({

最后要做的重要事情是不要直接导入JwtService。相反,JwtModule使用上面的代码进行初始化,扩展本身应该在内部JwtService正确初始化。

于 2021-10-19T14:25:28.573 回答
0

由于您AuthService在依赖注入容器中注册并且只是在监视registerUserAsync,因此它也需要JWTService注册。

您需要注册注入的依赖项AuthService

const moduleRef: TestingModule = await Test.createTestingModule({
  imports: [JwtModule],
  controllers: [AuthController],
  providers: [
    AuthService,
    UsersService,
    JWTService, // <--here
    {
      provide: getRepositoryToken(User),
      useClass: Repository,
    },
],
}).compile();

或注册一个AuthService不需要任何其他依赖项的完全模拟:

const moduleRef: TestingModule = await Test.createTestingModule({
  imports: [JwtModule],
  controllers: [AuthController],
  providers: [
    {
      provide: AuthService,
      useValue: {
        registerUserAsync: jest.fn(), // <--here
      }
     },
    {
      provide: getRepositoryToken(User),
      useClass: Repository,
    },
],
}).compile();

于 2020-07-11T02:19:30.897 回答