Skip to content

Commit

Permalink
test: 테스트 코드 작성 #ZUDA-59 (#14)
Browse files Browse the repository at this point in the history
* chore: add faker dependency and fix jest config

* test: 유저 생성 관련 테스트 코드 추가

* test: implement test code about user

* test: implement test code about exists and find function

* test: 불필요한 테스트 코드 삭제

* test: 유저 수정, 삭제 테스트코드 작성 및 유틸 함수 구현

- Add test code about updating and deleting user.
- Implement createUserMock() function to create user mockup.

* fix: fix typo

* HOTFIX: change column type in Room model from User to string

* feat: create test.util.ts for test code

* style: 함수 순서 정렬

* test: implement test code of RoomService

* chore(jenkins): add test script into Jenkinsfile

* test: create test code for AuthService
  • Loading branch information
SkyLightQP authored Jun 9, 2021
1 parent 7dd276c commit e112d98
Show file tree
Hide file tree
Showing 12 changed files with 963 additions and 65 deletions.
7 changes: 4 additions & 3 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pipeline {
agent any

tools {
nodejs "nodejs12"
}
Expand All @@ -18,10 +18,11 @@ pipeline {
}
}

stage('Lint') {
stage('Lint and Test') {
steps {
sh 'yarn'
sh 'yarn lint'
sh 'yarn test'
}
}

Expand Down Expand Up @@ -51,4 +52,4 @@ pipeline {
}
}
}
}
}
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"class-validator": "^0.13.1",
"cookie-parser": "^1.4.5",
"express": "^4.17.1",
"faker": "^5.5.3",
"helmet": "^4.4.1",
"mongoose": "^5.12.6",
"mysql2": "^2.2.5",
Expand All @@ -69,6 +70,7 @@
"@types/bcrypt": "^3.0.1",
"@types/cookie-parser": "^1.4.2",
"@types/express": "^4.17.11",
"@types/faker": "^5.5.6",
"@types/jest": "^26.0.20",
"@types/multer": "^1.4.5",
"@types/node": "^14.14.35",
Expand Down Expand Up @@ -101,6 +103,9 @@
"typescript": "^4.2.3"
},
"jest": {
"moduleNameMapper": {
"^src/(.*)$": "<rootDir>/$1"
},
"moduleFileExtensions": [
"js",
"json",
Expand Down
166 changes: 166 additions & 0 deletions src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import { Test, TestingModule } from '@nestjs/testing';
import faker from 'faker';
import { JwtModule, JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { getRepositoryToken } from '@nestjs/typeorm';
import bcrypt from 'bcrypt';
import { AuthService } from './auth.service';
import { UserService } from '../user/user.service';
import { User } from '../user/user.entity';
import { createUserMock } from '../utils/test.util';

const mockRepository = () => ({
find: jest.fn(),
findOne: jest.fn(),
save: jest.fn(),
create: jest.fn(),
softRemove: jest.fn()
});

describe('AuthService', () => {
let authService: AuthService;
let jwtService: JwtService;
let userService: UserService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [
JwtModule.register({
secret: 'asdfghjkl'
})
],
providers: [
{
provide: ConfigService,
useValue: {
get: jest.fn((key: string) => {
switch (key) {
case 'JWT_SECRET_EXPIRE_TIME':
return '5m';
case 'JWT_REFRESH_EXPIRE_TIME':
return '10m';
default:
return null;
}
})
}
},
UserService,
{
provide: getRepositoryToken(User),
useValue: mockRepository()
},
AuthService
]
}).compile();

authService = module.get<AuthService>(AuthService);
jwtService = module.get<JwtService>(JwtService);
userService = module.get<UserService>(UserService);
});

describe('Generate Token', () => {
it('새로운 AccessToken을 만든다.', () => {
const uuidMock = faker.datatype.uuid();

const result = authService.generateToken(uuidMock);
expect(result).toStrictEqual({
TOKEN: expect.any(String)
});
});

it('새로운 RefreshToken을 만든다.', () => {
const uuidMock = faker.datatype.uuid();

const result = authService.refreshToken(uuidMock);
expect(result).toStrictEqual({
REFRESH_TOKEN: expect.any(String)
});
});
});

describe('Validate Token', () => {
it('AccessToken을 검증한다.', () => {
const uuidMock = faker.datatype.uuid();

const expectResult = {
iat: 1,
exp: 1,
uuid: uuidMock
};

const verifySpy = jest.spyOn(jwtService, 'verify').mockReturnValue(expectResult);

const jwt = authService.generateToken(uuidMock);
const result = authService.validateToken(jwt.TOKEN);

expect(verifySpy).toBeCalled();
expect(result).toBe(expectResult);
});
});

it('AccessToken이 잘못 되었다.', () => {
const jwt = 'invalid.token';
const result = authService.validateToken(jwt);

expect(result).toBe(undefined);
});

it('이메일과 비밀번호를 이용하여 계정을 검증한다.', async () => {
const email = faker.internet.email();
const password = faker.datatype.string();

const existsSpy = jest.spyOn(userService, 'existsUserByEmail').mockResolvedValue(true);
const findOneSpy = jest.spyOn(userService, 'findOneByEmail').mockResolvedValue(
createUserMock(
{ email },
{
password
}
)
);
const compareSpy = jest.spyOn(bcrypt, 'compare').mockResolvedValue(true);

const result = await authService.validateLocalLogin(email, password);

expect(existsSpy).toHaveBeenCalledWith(email);
expect(findOneSpy).toHaveBeenCalledWith(email);
expect(compareSpy).toBeCalled();
expect(result).toBeTruthy();
});

it('존재하지 않는 유저가 계정 검증을 시도한다.', async () => {
const email = faker.internet.email();
const password = faker.datatype.string();

const existsSpy = jest.spyOn(userService, 'existsUserByEmail').mockResolvedValue(false);

const result = await authService.validateLocalLogin(email, password);

expect(existsSpy).toHaveBeenCalledWith(email);
expect(result).toBeFalsy();
});

it('틀린 비밀번호로 계정 검증을 시도한다.', async () => {
const email = faker.internet.email();
const password = faker.datatype.string();

const existsSpy = jest.spyOn(userService, 'existsUserByEmail').mockResolvedValue(true);
const findOneSpy = jest.spyOn(userService, 'findOneByEmail').mockResolvedValue(
createUserMock(
{ email },
{
password
}
)
);
const compareSpy = jest.spyOn(bcrypt, 'compare').mockResolvedValue(false);

const result = await authService.validateLocalLogin(email, password);

expect(existsSpy).toHaveBeenCalledWith(email);
expect(findOneSpy).toHaveBeenCalledWith(email);
expect(compareSpy).toBeCalled();
expect(result).toBeFalsy();
});
});
4 changes: 2 additions & 2 deletions src/room/dto/create-room.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ export class CreateRoomDTO {
@IsString()
roomName!: string;

@IsObject()
owner!: User;
@IsString()
owner!: string;

@IsString()
maxPeople!: number;
Expand Down
7 changes: 2 additions & 5 deletions src/room/room.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,14 @@ export class RoomController {
@ApiNotFoundResponse()
@ApiConflictResponse()
async create(@Body() createRoomBodyDto: CreateRoomBodyDTO): Promise<Room> {
const uuid = createRoomBodyDto.owner;
const user = await this.userService.findOneByUUID(uuid);

const createRoomDto = new CreateRoomDTO();
createRoomDto.roomName = createRoomBodyDto.roomName;
createRoomDto.owner = user;
createRoomDto.owner = createRoomBodyDto.owner;
createRoomDto.maxPeople = createRoomBodyDto.maxPeople;

const room = await this.roomService.create(createRoomDto);
await this.roomControllService.joinRoom(room.roomId, {
userId: uuid
userId: createRoomBodyDto.owner
});
return room;
}
Expand Down
2 changes: 1 addition & 1 deletion src/room/room.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ export class Room {
onDelete: 'CASCADE'
})
@JoinColumn({ name: 'owner' })
owner!: User;
owner!: string;
}
Loading

0 comments on commit e112d98

Please sign in to comment.