Skip to content

Commit

Permalink
test(namingRule): change test code namingRule
Browse files Browse the repository at this point in the history
  • Loading branch information
astorverse committed Aug 7, 2024
1 parent c25e866 commit f596850
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 113 deletions.
27 changes: 24 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ erDiagram
- **컨트롤러 메서드**: HTTP 요청 중점 네이밍
- 생성: `create{Entity}`
- 조회: `get{Entity}`, `get{Entities}`
- 업데이트: `patch{Entity}`, `put{Entity}`
- 업데이트: `patch{Entity}`, `put{Entity}`
- 삭제: `delete{Entity}`
- **서비스 메서드**: Entity 명시
- 생성: `create{Entity}`
Expand All @@ -273,9 +273,30 @@ erDiagram

## 테스트 코드 네이밍 룰

{메서드명}{기대결과}{테스트상태}
```
describe('{layer}',()=>{
describe('{method}',async ()=>{
it('should {result}{condition}',()=>{})
})
})
```

`isAdult_False_AgeLessThan18)`
` AgreementsService
createAgreement
✓ should return AgreementDto with valid input (6 ms)
existCheck
✓ should throw exception when agreement does not exist (5 ms)
✓ should return AgreementDto when agreement exists (2 ms)
findAgreement
✓ should return AgreementDto with valid input (1 ms)
findAgreements
✓ should return AgreementDtos with valid input (1 ms)
patchAgreement
✓ should return AgreementDto with valid input (1 ms)
✓ should throw exception for invalid agreementId (1 ms)
✓ should throw exception for invalid userId (1 ms)`

## 접두사 정리

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"deploy:staging": "./deploy/deploy-staging.sh",
"deploy:prod": "./deploy/deploy-prod.sh",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test": "jest --verbose",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
Expand Down
58 changes: 58 additions & 0 deletions src/APIs/agreements/__test__/agreements.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Test, TestingModule } from '@nestjs/testing';
import { AgreementsService } from '../agreements.service';
import { AgreementDto } from '../dtos/common/agreement.dto';
import {
MockService,
MockServiceFactory,
TEST_DATE_FIELDS,
} from '@/utils/test.utils';
import { AgreementType } from '@/common/enums/agreement-type.enum';
import { AgreementsController } from '../agreements.controller';
import { AgreementCreateRequestDto } from '../dtos/request/agreement-create-request.dto';
import { Request } from 'express';

describe('AgreementsService', () => {
let ctrl_agreements: AgreementsController;
let svc_agreements: MockService<AgreementsService>;
let dto_agreement: AgreementDto;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [AgreementsController],
providers: [
{
provide: AgreementsService,
useValue: MockServiceFactory.getMockService(AgreementsService),
},
],
}).compile();
ctrl_agreements = module.get<AgreementsController>(AgreementsController);
svc_agreements =
module.get<MockService<AgreementsService>>(AgreementsService);
dto_agreement = {
id: 1,
userId: 1,
agreementType: AgreementType.TERMS_OF_SERVICE,
isAgreed: true,
...TEST_DATE_FIELDS,
};
});

describe('agree', () => {
it('should return AgreementDto with valid input', async () => {
const req = { user: { userId: 1 } } as Request;
const dto: AgreementCreateRequestDto = {
agreementType: AgreementType.TERMS_OF_SERVICE,
isAgreed: true,
};
svc_agreements.createAgreement.mockResolvedValue(dto_agreement);

const result = await ctrl_agreements.agree(req, dto);
expect(result).toEqual(dto_agreement);
expect(svc_agreements.createAgreement).toHaveBeenCalledWith({
...dto,
userId: 1,
});
});
});
});
226 changes: 117 additions & 109 deletions src/APIs/agreements/__test__/agreements.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,131 +54,139 @@ describe('AgreementsService', () => {
...TEST_DATE_FIELDS,
};
});

it('createAgreement_AgreementDto_ValidInput', async () => {
const createAgreementInput: IAgreementsServiceCreate = {
userId: 1,
agreementType: AgreementType.TERMS_OF_SERVICE,
isAgreed: true,
};
const createAgreementOutput: AgreementDto = {
id: 1,
...createAgreementInput,
...TEST_DATE_FIELDS,
};
repo_agreements.save.mockResolvedValue(createAgreementOutput);
const result = await svc_agreements.createAgreement(createAgreementInput);
expect(result).toEqual(createAgreementOutput);
expect(repo_agreements.save).toHaveBeenCalledWith(createAgreementInput);
describe('createAgreement', () => {
it('should return AgreementDto with valid input', async () => {
const createAgreementInput: IAgreementsServiceCreate = {
userId: 1,
agreementType: AgreementType.TERMS_OF_SERVICE,
isAgreed: true,
};
const createAgreementOutput: AgreementDto = {
id: 1,
...createAgreementInput,
...TEST_DATE_FIELDS,
};
repo_agreements.save.mockResolvedValue(createAgreementOutput);
const result = await svc_agreements.createAgreement(createAgreementInput);
expect(result).toEqual(createAgreementOutput);
expect(repo_agreements.save).toHaveBeenCalledWith(createAgreementInput);
});
});

it('existCheck_ThrowError_NotExist', async () => {
const existCheckInput: IAgreementsServiceId = { agreementId: 1 };
const findOneOutput: AgreementDto = null;
repo_agreements.findOne.mockResolvedValue(findOneOutput);
await expect(svc_agreements.existCheck(existCheckInput)).rejects.toThrow(
BlccuExceptionTest('AGREEMENT_NOT_FOUND'),
);
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: existCheckInput.agreementId },
describe('existCheck', () => {
it('should throw exception when agreement does not exist', async () => {
const existCheckInput: IAgreementsServiceId = { agreementId: 1 };
const findOneOutput: AgreementDto = null;
repo_agreements.findOne.mockResolvedValue(findOneOutput);
await expect(svc_agreements.existCheck(existCheckInput)).rejects.toThrow(
BlccuExceptionTest('AGREEMENT_NOT_FOUND'),
);
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: existCheckInput.agreementId },
});
});
});

it('existCheck_AgreementDto_WhenExist', async () => {
const existCheckInput: IAgreementsServiceId = { agreementId: 1 };
repo_agreements.findOne.mockResolvedValue(dto_agreement);
await expect(svc_agreements.existCheck(existCheckInput)).resolves.toEqual(
dto_agreement,
);
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: existCheckInput.agreementId },
it('should return AgreementDto when agreement exists', async () => {
const existCheckInput: IAgreementsServiceId = { agreementId: 1 };
repo_agreements.findOne.mockResolvedValue(dto_agreement);
await expect(svc_agreements.existCheck(existCheckInput)).resolves.toEqual(
dto_agreement,
);
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: existCheckInput.agreementId },
});
});
});

it('findAgreement_AgreementDto_ValidInput', async () => {
const findAgreementInput: IAgreementsServiceId = { agreementId: 1 };
repo_agreements.findOne.mockResolvedValue(dto_agreement);
await expect(
svc_agreements.findAgreement(findAgreementInput),
).resolves.toEqual(dto_agreement);
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: findAgreementInput.agreementId },
describe('findAgreement', () => {
it('should return AgreementDto with valid input', async () => {
const findAgreementInput: IAgreementsServiceId = { agreementId: 1 };
repo_agreements.findOne.mockResolvedValue(dto_agreement);
await expect(
svc_agreements.findAgreement(findAgreementInput),
).resolves.toEqual(dto_agreement);
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: findAgreementInput.agreementId },
});
});
});

it('findAgreements_AgreementDtos_ValidInput', async () => {
const findAgreementsInput: IAgreementsServiceUserId = { userId: 1 };
repo_agreements.find.mockResolvedValue([dto_agreement]);
await expect(
svc_agreements.findAgreements(findAgreementsInput),
).resolves.toEqual([dto_agreement]);
expect(repo_agreements.find).toHaveBeenCalledWith({
where: { user: { id: findAgreementsInput.userId } },
describe('findAgreements', () => {
it('should return AgreementDtos with valid input', async () => {
const findAgreementsInput: IAgreementsServiceUserId = { userId: 1 };
repo_agreements.find.mockResolvedValue([dto_agreement]);
await expect(
svc_agreements.findAgreements(findAgreementsInput),
).resolves.toEqual([dto_agreement]);
expect(repo_agreements.find).toHaveBeenCalledWith({
where: { user: { id: findAgreementsInput.userId } },
});
});
});

it('patchAgreement_AgreementDto_ValidInput', async () => {
const patchAgreementInput: IAgreementsServicePatchAgreement = {
userId: 1,
agreementId: 1,
isAgreed: true,
};
const saveOutput: AgreementDto = {
...dto_agreement,
isAgreed: patchAgreementInput.isAgreed,
};
repo_agreements.findOne.mockResolvedValue(dto_agreement);
repo_agreements.save.mockResolvedValue(saveOutput);
expect(await svc_agreements.patchAgreement(patchAgreementInput)).toEqual(
saveOutput,
);
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: patchAgreementInput.agreementId },
describe('patchAgreement', () => {
it('should return AgreementDto with valid input', async () => {
const patchAgreementInput: IAgreementsServicePatchAgreement = {
userId: 1,
agreementId: 1,
isAgreed: true,
};
const saveOutput: AgreementDto = {
...dto_agreement,
isAgreed: patchAgreementInput.isAgreed,
};
repo_agreements.findOne.mockResolvedValue(dto_agreement);
repo_agreements.save.mockResolvedValue(saveOutput);
expect(await svc_agreements.patchAgreement(patchAgreementInput)).toEqual(
saveOutput,
);
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: patchAgreementInput.agreementId },
});
expect(repo_agreements.save).toHaveBeenCalledWith({
...dto_agreement,
isAgreed: patchAgreementInput.isAgreed,
});
});
expect(repo_agreements.save).toHaveBeenCalledWith({
...dto_agreement,
isAgreed: patchAgreementInput.isAgreed,
});
});

it('patchAgreement_AgreementDto_InvalidAgreementId', async () => {
const patchAgreementInput: IAgreementsServicePatchAgreement = {
userId: 1,
agreementId: 1,
isAgreed: true,
};
const findOneOutput: AgreementDto = null;
const saveOutput: AgreementDto = {
...findOneOutput,
isAgreed: patchAgreementInput.isAgreed,
};
repo_agreements.findOne.mockResolvedValue(findOneOutput);
repo_agreements.save.mockResolvedValue(saveOutput);
await expect(
svc_agreements.patchAgreement(patchAgreementInput),
).rejects.toThrow(BlccuExceptionTest('AGREEMENT_NOT_FOUND'));
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: patchAgreementInput.agreementId },
it('should throw exception for invalid agreementId', async () => {
const patchAgreementInput: IAgreementsServicePatchAgreement = {
userId: 1,
agreementId: 1,
isAgreed: true,
};
const findOneOutput: AgreementDto = null;
const saveOutput: AgreementDto = {
...findOneOutput,
isAgreed: patchAgreementInput.isAgreed,
};
repo_agreements.findOne.mockResolvedValue(findOneOutput);
repo_agreements.save.mockResolvedValue(saveOutput);
await expect(
svc_agreements.patchAgreement(patchAgreementInput),
).rejects.toThrow(BlccuExceptionTest('AGREEMENT_NOT_FOUND'));
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: patchAgreementInput.agreementId },
});
});
});

it('patchAgreement_AgreementDto_InvalidUserId', async () => {
const patchAgreementInput: IAgreementsServicePatchAgreement = {
userId: 2,
agreementId: 1,
isAgreed: true,
};
const saveOutput: AgreementDto = {
...dto_agreement,
isAgreed: patchAgreementInput.isAgreed,
};
repo_agreements.findOne.mockResolvedValue(dto_agreement);
repo_agreements.save.mockResolvedValue(saveOutput);
await expect(
svc_agreements.patchAgreement(patchAgreementInput),
).rejects.toThrow(BlccuExceptionTest('NOT_THE_OWNER'));
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: patchAgreementInput.agreementId },
it('should throw exception for invalid userId', async () => {
const patchAgreementInput: IAgreementsServicePatchAgreement = {
userId: 2,
agreementId: 1,
isAgreed: true,
};
const saveOutput: AgreementDto = {
...dto_agreement,
isAgreed: patchAgreementInput.isAgreed,
};
repo_agreements.findOne.mockResolvedValue(dto_agreement);
repo_agreements.save.mockResolvedValue(saveOutput);
await expect(
svc_agreements.patchAgreement(patchAgreementInput),
).rejects.toThrow(BlccuExceptionTest('NOT_THE_OWNER'));
expect(repo_agreements.findOne).toHaveBeenCalledWith({
where: { id: patchAgreementInput.agreementId },
});
});
});
});
19 changes: 19 additions & 0 deletions src/utils/test.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ export type MockRepository<T = any> = {
[P in keyof T]?: jest.Mock<any>;
};

export type MockService<T = any> = {
[P in keyof T]?: jest.Mock<any>;
};

export class MockRepositoryFactory {
static getMockRepository<T>(
type: new (...args: any[]) => T,
Expand Down Expand Up @@ -34,3 +38,18 @@ export const TEST_DATE_FIELDS = {
dateUpdated: expect.any(Date),
dateDeleted: expect.any(Date),
};

export class MockServiceFactory {
static getMockService<T>(type: new (...args: any[]) => T): MockService<T> {
const mockService: MockService<T> = {};

// 서비스 클래스의 메서드를 jest.fn()으로 대체
Object.getOwnPropertyNames(type.prototype)
.filter((key: string) => key !== 'constructor')
.forEach((key: string) => {
mockService[key] = jest.fn<any>();
});

return mockService;
}
}

0 comments on commit f596850

Please sign in to comment.