티스토리 뷰
[ Cannot find module 해결하기 ]
(에러문)
Cannot find module 'src/entities/enums/PostType' from 'posts/posts.service.ts'
(해결책)
package.json 에서 "roots", "modulePaths", "moduleDirectories", "moduleNameMapper" 추가
moduleNameMapper 은 jest가 파일을 찾는 방식을 나타낸다.
jest는 절대경로를 파악하지 못하고, 상대경로로 파일의 위치를 파악한다.
{
... ,
"jest": {
"moduleFileExtensions": ["js","json","ts"],
"rootDir": "src",
"roots": [ "<rootDir>" ],
"modulePaths": [ "<rootDir>" ],
"moduleDirectories": [ "node_modules" ],
"moduleNameMapper": { "^src/(.*)$": "<rootDir>/$1" },
...,
}
}
[참고]
[ DataSource 를 찾지 못하는 에러 ]
Nest can't resolve dependencies... Please make sure that the argument DataSource at index[0] is available in the RootTestModule context.
Nest can't resolve dependencies of the PostsService (?, PostsRepository). Please make sure that the argument DataSource at index [0] is available in the RootTestModule context.
(에러해석)
PostService는 repository가 필요한데, 테스트 모듈에서는 repository를 제공하지 않아서 생기는 문제이다.
(원인)
// posts.service.spec.ts
describe('PostsService', () => {
let service: PostsService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [PostsService],
}).compile();
service = module.get<PostsService>(PostsService);
});
...
}
(시도1)
posts.module.ts 에 내가 주입한 엔티티를 확인할 수 있다.
/// posts.module.ts
import { Module } from '@nestjs/common';
import { PostsService } from './posts.service';
import { PostsController } from './posts.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Posts } from '../entities/Posts';
@Module({
imports: [TypeOrmModule.forFeature([Posts])], // 내가 주입한 엔티티들
controllers: [PostsController],
providers: [PostsService],
})
export class PostsModule {}
createTestingModule에
imports: [ TypeOrmModule.forRoot(), TypeOrmModule.forFeature([ 엔티티 ] )] 를 추가한다.
// posts.servicee.spec.ts
describe('PostsService', () => {
let service: PostsService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [TypeOrmModule.forRoot(), TypeOrmModule.forFeature([Posts])], // 추가
providers: [PostsService],
}).compile();
service = module.get<PostsService>(PostsService);
});
}
이번엔... 시간초과가 떴다... 데이터베이스에 접근하지 못했다는 것이다.
다른 방법을 찾아봐야겠다 ㅠㅠ
[참고]
[ Joi 설치하여, Mock 데이터베이스 만들기 ]
- 패키지 설치
$ npm i @nestjs/config @nestjs/mapped-types @nestjs/typeorm typeorm mysql2 joi
$ npm i class-validator class-transformer
- app.module.ts
import * as Joi from 'joi';
@Module({
imports: [
ConfigModule.forRoot({
envFilePath: '.env',
isGlobal: true,
validationSchema: Joi.object({
NODE_PORT: Joi.string().required(),
MYSQL_HOST: Joi.string().required(),
MYSQL_PORT: Joi.string().required(),
MYSQL_USERNAME: Joi.string().required(),
MYSQL_PASSWORD: Joi.string().required(),
MYSQL_DATABASE: Joi.string().required(),
}),
}),
TypeOrmModule.forRootAsync({
imports: [MySqlConfigModule],
useClass: MySqlConfigService,
}),
AuthModule,
PostsModule,
],
controllers: [AppController],
providers: [
{ provide: APP_FILTER, useClass: HttpExceptionFilter },
AppService,
],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer): any {
consumer.apply(LoggerMiddleware).forRoutes('*');
}
}
- posts.module.ts
import { Module } from '@nestjs/common';
import { PostsService } from './posts.service';
import { PostsController } from './posts.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Posts } from '../entities/Posts';
@Module({
imports: [TypeOrmModule.forFeature([Posts])],
controllers: [PostsController],
providers: [PostsService],
})
export class PostsModule {}
- 테스트 를 위한 패키지 설치
$ npm i -D @nestjs/testing
"npm run test" 로 테스트 케이스를 실행시켜봤지만 또에러가 나왔다 ...ㅎ
[에러]
Nest could not find PostsService element (this provider does not exist in the current context)
26 | }).compile();
27 |
> 28 | service = module.get<PostsService>(PostsService);
29 | postRepository = module.get<MockRepository<Posts>>(
30 | getRepositoryToken(Posts),
31 | );
at InstanceLinksHost.get (../node_modules/@nestjs/core/injector/instance-links-host.js:15:19)
at TestingModule.find (../node_modules/@nestjs/core/nest-application-context.js:221:55)
at TestingModule.get (../node_modules/@nestjs/core/nest-application-context.js:54:20)
at Object.<anonymous> (posts/test/posts.service.spec.ts:28:22)
Jest의 테스트케이스를 불러올 때, 테스트 대상 서비스의 생성자의 필드를 확인해야한다.
(수정이전)
// posts.service.ts
@Injectable()
export class PostsService {
constructor(
private dataSource: DataSource,
@InjectRepository(Posts)
private readonly postsRepository: Repository<Posts>,
) {}
...
}
(수정후)
// posts.service.ts
@Injectable()
export class PostsService {
constructor(
@InjectRepository(Posts)
private readonly postsRepository: Repository<Posts>,
) {}
...
}
// posts.service.spec.ts
const mockPostRepository = () => ({
save: jest.fn(),
find: jest.fn(),
findOne: jest.fn(),
softDelete: jest.fn(),
});
type MockRepository<T = any> = Partial<Record<keyof Repository<T>, jest.Mock>>;
describe('PostsService', () => {
let service: PostsService;
let postRepository: MockRepository<Posts>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
PostsService,
{
provide: getRepositoryToken(Posts),
useValue: mockPostRepository(),
},
],
}).compile();
service = module.get<PostsService>(PostsService);
postRepository = module.get<MockRepository<Posts>>(
getRepositoryToken(Posts),
);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
...
});
내가 DataSource를 사용한 이유는 QueryRunner을 호출하여 transaction 처리를 위해서였다.
여러개의 sql문을 호출할 때의 경우에서
문제가 발생하면 rollback하고, 문제가 없으면 commit처리해서 트랜잭션 관리를 위해서 했다.
서비스 생성자에서 DataSource 를 지웠더니 jest 테스트가 정상동작하게 되었다.
조금 궁금한게 생겼다. QueryRunner 와 QueryBuilder 의 차이가 뭔지 궁금했다.
내가 기억하기로는, QueryRunner은 수동으로 트랜잭션을 관리하고, QueryBuilder은 자동으로 관리하는걸로 알고있다.
이번에는 테스트케이스를 추가했더니... createQueryBuilder를 모르는 에러가 떴다.
TypeError: this.postsRepository.createQueryBuilder(...).insert(...).into is not a function
76 | .createQueryBuilder('posts')
77 | .insert()
> 78 | .into(Posts)
| ^
79 | .values({
80 | ...createPostDto,
81 | userId: user.userId,
(해결책) mockRepository 에서 createQueryBuilder 을 정의를 해줘야한다.
// posts.service.spec.ts
const mockPostRepository = jest.fn(() => ({
create: jest.fn(),
save: jest.fn(),
find: jest.fn(),
findOne: jest.fn(),
softDelete: jest.fn(),
createQueryBuilder: jest.fn().mockReturnValue({
insert: jest.fn().mockReturnThis(),
into: jest.fn().mockReturnThis(),
values: jest.fn().mockReturnThis(),
execute: jest.fn().mockReturnThis(),
}),
}));
type MockRepository<T = any> = Partial<Record<keyof Repository<T>, jest.Mock>>;
describe('PostsService', () => {
let service: PostsService;
let postRepository: MockRepository<Posts>;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
PostsService,
{
provide: getRepositoryToken(Posts),
useValue: mockPostRepository(),
},
],
}).compile();
service = module.get<PostsService>(PostsService);
postRepository = module.get<MockRepository<Posts>>(
getRepositoryToken(Posts),
);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
describe('Public-Post', () => {
const newPublicPost: CreatePostDto = {
title: '공개 게시글 테스트',
content: '공개 게시글의 본문입니다 ~~~~😺',
postType: PostType.PUBLIC_POST,
};
const user = new Users();
user.userId = 1;
user.name = '기스깅';
it('공개 게시글 등록 성공', async () => {
postRepository.save.mockResolvedValueOnce(newPublicPost); // 등록성공 가정
const result = await service.createPost(user, newPublicPost);
expect(postRepository.save).toBeCalled(); // save 가 불러졌음.
expect(postRepository.save).toHaveBeenCalledWith(newPublicPost);
expect(result).toEqual(newPublicPost); // 이 createPosts() method결과가 newPublicPosts가 와 같니?
});
it.todo('공개 게시글 등록 실패 - 제목길이 20자 초과');
it.todo('공개 게시글 등록 실패 - 본문길이 200자 초과');
});
});
[참고]
< Unit Test for QueryBuilder >
[ Cannot find module 'passport' 에러 ]
(해결책)
$ npm i passport
$ npm i -D @types/passport
[ validationSchema: Joi.object({ ... }) ]
(원인)
import Joi from 'joi';
(해결책)
import * as Joi from 'joi';
단위 테스트 케이스 예제
'Backend > 꾸준히 TIL' 카테고리의 다른 글
[NestJS] Custom 에러 만들기 와 Exception Filter (0) | 2022.11.08 |
---|---|
[NestJS+TypeORM] Pagination 처리 (0) | 2022.11.07 |
[NestJS + regex] 정규표현식 활용하기 (0) | 2022.11.05 |
[NestJS + TypeORM] 소수넘버 필드, 길이 설정 (0) | 2022.11.05 |
[에러 해결] Cannot find module bcrypt_lib.node (0) | 2022.11.05 |
- Total
- Today
- Yesterday
- MongoDB
- 갓생살자
- nestjs
- git
- jest
- TypeScript
- RDBMS
- gem
- TDD
- MySQL
- 한달어스
- 디지털디톡스
- 스마트폰중독
- 개발용어
- 습관개선
- 참고
- IT용어
- typeORM
- 바이트디그리
- Mongoose
- node.js
- Jekyll
- vscode
- 나도 할 수 있다
- nestjs jest
- Nest.js
- OS
- 클린아키텍쳐
- 미완
- 한달독서
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |