Модульное тестирование NestJS / TypeORM: не удается разрешить зависимости JwtService - PullRequest
0 голосов
/ 09 июля 2020

Я пытаюсь провести модульное тестирование этого контроллера и высмеять необходимые ему службы / репозитории.

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

1 голос
/ 10 июля 2020

Здесь я заметил несколько вещей:

  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(), и сохранить их в переменной, чтобы позже добавить к ним макеты. Вы можете проверить этот репозиторий тестирования , в котором есть много других примеров.

0 голосов
/ 11 июля 2020

Поскольку вы регистрируете 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();

...