Ваш вопрос, кажется, не привлек много внимания, так как я столкнулся с той же проблемой, вот решение, которое я реализовал.Надеюсь, что это поможет другим энтузиастам NestJS!
Понимание модели mongoose
Получаемое сообщение об ошибке совершенно очевидно: this.userModel
действительно не конструктор, так как вы предоставили пустой объект для useValue
,Чтобы гарантировать правильное внедрение, useValue
должен быть подклассом mongoose.Model
.Мангуста github repo сама дает непротиворечивое объяснение базовой концепции (из строки 63):
* In Mongoose, the term "Model" refers to subclasses of the `mongoose.Model`
* class. You should not use the `mongoose.Model` class directly. The
* [`mongoose.model()`](./api.html#mongoose_Mongoose-model) and
* [`connection.model()`](./api.html#connection_Connection-model) functions
* create subclasses of `mongoose.Model` as shown below.
Другими словами, модель мангуста - это класс с несколькими методами, которые пытаютсяподключиться к базе данных.В нашем случае единственным используемым методом Model является save()
.Mongoose использует синтаксис функции конструктора javascript, тот же синтаксис может использоваться для написания нашего макета.
TL; DR
Макет должен быть функцией конструктора с параметром save()
.
Написание макета
Сервисный тест заключается в следующем:
beforeEach(async () => {
function mockUserModel(dto: any) {
this.data = dto;
this.save = () => {
return this.data;
};
}
const module = await Test.createTestingModule({
providers: [
AuthenticationService,
{
provide: getModelToken('User'),
useValue: mockUserModel,
},
],
}).compile();
authenticationService = module.get<AuthenticationService>(AuthenticationService);
});
Я также провел небольшой рефакторинг, чтобы обернуть все в блоке beforeEach
.Реализация save()
, которую я выбрал для своих тестов, представляет собой простую функцию идентификации, но вы можете реализовать ее по-разному, в зависимости от того, как вы хотите утверждать возвращаемое значение createUser()
.
Ограничения этого решения
Одной из проблем этого решения является именно то, что вы утверждаете на возвращаемое значение функции, но не можете утверждать на количество вызовов, так как save()
не является jest.fn()
.Я не смог найти способ использовать module.get
для доступа к токену модели за пределами области видимости модуля.Если кто-нибудь найдет способ сделать это, пожалуйста, сообщите мне.
Другая проблема заключается в том, что экземпляр userModel
должен быть создан в тестируемом классе.Это проблематично, например, когда вы хотите протестировать findById()
, так как модель не создается, но метод вызывается для коллекции.Обходной путь заключается в добавлении ключевого слова new
на уровне useValue
:
const module = await Test.createTestingModule({
providers: [
AuthenticationService,
{
provide: getModelToken('User'),
useValue: new mockUserModel(),
},
],
}).compile();
Еще одна вещь ...
Синтаксис return await
использовать не следует, так каквыдает ошибку ts-lint (правило: нет возврата-ожидание).См. Связанную проблему github doc .