NestJS / TypeORM单元测试:无法解析JwtService的依赖项

时间:2020-07-09 20:12:03

标签: jestjs nestjs typeorm nestjs-jwt

我正在尝试对该控制器进行单元测试,并模拟掉它所需的服务/存储库。

@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)

我不太确定如何进行操作,因此需要一些帮助。

2 个答案:

答案 0 :(得分:1)

这里有几件事我需要注意:

  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();
});

现在,您可以使用modRef.get()获取身份验证服务和用户服务,并将它们保存到变量中,以便稍后添加模拟。您可以查看this testing repository,其中还有很多其他示例。

答案 1 :(得分: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();