Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

엣지 API 테스트코드 작성 #193

Merged
merged 3 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,4 @@ lerna-debug.log*

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
apps/backend/db.sqlite
Empty file added .vscode/settings.json
Empty file.
97 changes: 96 additions & 1 deletion apps/backend/src/edge/edge.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,120 @@
import { Test, TestingModule } from '@nestjs/testing';
import { EdgeController } from './edge.controller';
import { EdgeService } from './edge.service';
import { CreateEdgeDto } from './dtos/createEdge.dto';
import { EdgeResponseMessage } from './edge.controller';
import { EdgeNotFoundException } from '../exception/edge.exception';
import { Edge } from './edge.entity';
import { Node } from '../node/node.entity';

describe('EdgeController', () => {
let controller: EdgeController;
let edgeService: EdgeService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [EdgeController],
providers: [
{
provide: EdgeService,
useValue: {},
useValue: {
createEdge: jest.fn(),
deleteEdge: jest.fn(),
findEdges: jest.fn(),
},
},
],
}).compile();

controller = module.get<EdgeController>(EdgeController);
edgeService = module.get<EdgeService>(EdgeService);
});

it('컨트롤러 클래스가 정상적으로 인스턴스화된다.', () => {
expect(controller).toBeDefined();
});

describe('createEdge', () => {
it('엣지가 성공적으로 만들어진다', async () => {
const dto: CreateEdgeDto = { fromNode: 1, toNode: 3 };
const expectedResponse = {
message: EdgeResponseMessage.EDGE_CREATED,
};

jest.spyOn(edgeService, 'createEdge').mockResolvedValue(undefined);
const result = await controller.createEdge(dto);

expect(edgeService.createEdge).toHaveBeenCalledWith(dto);
expect(result).toEqual(expectedResponse);
});
});

describe('deleteEdge', () => {
it('id에 해당하는 엣지를 찾아 삭제한다.', async () => {
const id = 2;
const expectedResponse = {
message: EdgeResponseMessage.EDGE_DELETED,
};

const result = await controller.deleteEdge(id);

expect(edgeService.deleteEdge).toHaveBeenCalledWith(id);
expect(result).toEqual(expectedResponse);
});

it('id에 해당하는 엣지가 존재하지 않으면 NodeNotFoundException을 throw한다.', async () => {
jest
.spyOn(edgeService, 'deleteEdge')
.mockRejectedValue(new EdgeNotFoundException());

await expect(controller.deleteEdge(1)).rejects.toThrow(
EdgeNotFoundException,
);
});
});

describe('findEdges', () => {
it('모든 엣지 목록을 반환한다.', async () => {
const node3 = {
id: 3,
x: 0,
y: 0,
title: 'Node Title',
page: null,
outgoingEdges: [],
incomingEdges: [],
} as Node;
const node4 = {
id: 4,
x: 0,
y: 0,
title: 'Node Title',
page: null,
outgoingEdges: [],
incomingEdges: [],
} as Node;
const node5 = {
id: 5,
x: 0,
y: 0,
title: 'Node Title',
page: null,
outgoingEdges: [],
incomingEdges: [],
} as Node;

const expectedEdges = [
{ id: 1, fromNode: node3, toNode: node5 },
{ id: 2, fromNode: node3, toNode: node4 },
] as Edge[];
node3.outgoingEdges = [];

jest.spyOn(edgeService, 'findEdges').mockResolvedValue(expectedEdges);

await expect(controller.findEdges()).resolves.toEqual({
message: EdgeResponseMessage.EDGE_ALL_RETURNED,
edges: expectedEdges,
});
});
});
});
8 changes: 4 additions & 4 deletions apps/backend/src/edge/edge.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ export class EdgeController {
})
@Get('/')
@HttpCode(HttpStatus.OK)
async getNodes() {
const nodes = await this.edgeService.findEdges();
async findEdges() {
const edges = await this.edgeService.findEdges();
return {
message: EdgeResponseMessage.EDGE_ALL_RETURNED,
nodes: nodes,
edges: edges,
};
}

Expand All @@ -56,7 +56,7 @@ export class EdgeController {
@ApiOperation({ summary: '엣지를 삭제합니다.' })
@Delete('/:id')
@HttpCode(HttpStatus.OK)
async deleteNode(
async deleteEdge(
@Param('id', ParseIntPipe) id: number,
): Promise<{ message: string }> {
await this.edgeService.deleteEdge(id);
Expand Down
10 changes: 5 additions & 5 deletions apps/backend/src/edge/edge.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
// Column,
ManyToOne,
JoinColumn,
} from 'typeorm';
Expand All @@ -21,9 +21,9 @@ export class Edge {
@JoinColumn({ name: 'to_node_id' })
toNode: Node;

@Column({ nullable: true })
type: string;
// @Column({ nullable: true })
// type: string;

@Column({ nullable: true })
color: string;
// @Column({ nullable: true })
// color: string;
}
166 changes: 164 additions & 2 deletions apps/backend/src/edge/edge.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,191 @@ import { Test, TestingModule } from '@nestjs/testing';
import { EdgeService } from './edge.service';
import { EdgeRepository } from './edge.repository';
import { NodeRepository } from '../node/node.repository';
import { CreateEdgeDto } from './dtos/createEdge.dto';
import { Edge } from './edge.entity';
import { Node } from '../node/node.entity';
import { EdgeNotFoundException } from '../exception/edge.exception';

describe('EdgeService', () => {
let service: EdgeService;
let edgeRepository: jest.Mocked<EdgeRepository>;
let nodeRepository: jest.Mocked<NodeRepository>;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
EdgeService,
{
provide: EdgeRepository,
useValue: {},
useValue: {
create: jest.fn(),
save: jest.fn(),
delete: jest.fn(),
findOneBy: jest.fn(),
find: jest.fn(),
},
},
{
provide: NodeRepository,
useValue: {},
useValue: {
save: jest.fn(),
findOneBy: jest.fn(),
},
},
],
}).compile();

service = module.get<EdgeService>(EdgeService);
edgeRepository = module.get(EdgeRepository);
nodeRepository = module.get(NodeRepository);
});

it('서비스 클래스가 정상적으로 인스턴스화된다.', () => {
expect(service).toBeDefined();
});

describe('createEdge', () => {
it('새로운 엣지를 만들어 노드와 노드를 연결하는 연결한다.', async () => {
const dto: CreateEdgeDto = { fromNode: 3, toNode: 5 };
const fromNode = {
id: 3,
x: 0,
y: 0,
title: 'Node Title',
page: null,
outgoingEdges: [],
incomingEdges: [],
} as Node;
const toNode = {
id: 5,
x: 0,
y: 0,
title: 'Node Title',
page: null,
outgoingEdges: [],
incomingEdges: [],
} as Node;
const edge = {
id: 1,
fromNode: fromNode,
toNode: toNode,
} as Edge;

jest
.spyOn(nodeRepository, 'findOneBy')
.mockResolvedValueOnce(fromNode) // 첫 번째 호출: fromNode
.mockResolvedValueOnce(toNode); // 두 번째 호출: toNode
jest.spyOn(edgeRepository, 'save').mockResolvedValue(edge);

const result = await service.createEdge(dto);

expect(result).toEqual(edge);
expect(edgeRepository.save).toHaveBeenCalledTimes(1);
expect(nodeRepository.findOneBy).toHaveBeenCalledTimes(2);
});
});

describe('deleteEdge', () => {
it('엣지를 성공적으로 삭제한다.', async () => {
jest
.spyOn(edgeRepository, 'delete')
.mockResolvedValue({ affected: true } as any);
jest.spyOn(edgeRepository, 'findOneBy').mockResolvedValue(new Edge());

await service.deleteEdge(1);

expect(edgeRepository.delete).toHaveBeenCalledWith(1);
});

it('삭제할 엣지가 존재하지 않으면 EdgeNotFoundException을 throw한다.', async () => {
jest
.spyOn(edgeRepository, 'delete')
.mockResolvedValue({ affected: false } as any);
await expect(service.deleteEdge(1)).rejects.toThrow(
EdgeNotFoundException,
);
});
});

describe('findEdges', () => {
it('존재하는 모든 엣지를 반환한다.', async () => {
const node3 = {
id: 3,
x: 0,
y: 0,
title: 'Node Title',
page: null,
outgoingEdges: [],
incomingEdges: [],
} as Node;
const node4 = {
id: 4,
x: 0,
y: 0,
title: 'Node Title',
page: null,
outgoingEdges: [],
incomingEdges: [],
} as Node;
const node5 = {
id: 5,
x: 0,
y: 0,
title: 'Node Title',
page: null,
outgoingEdges: [],
incomingEdges: [],
} as Node;
const node7 = {
id: 7,
x: 0,
y: 0,
title: 'Node Title',
page: null,
outgoingEdges: [],
incomingEdges: [],
} as Node;

const expectedEdgeList = [
{
id: 1,
fromNode: node3,
toNode: node5,
} as Edge,
{
id: 2,
fromNode: node3,
toNode: node4,
} as Edge,
{
id: 3,
fromNode: node3,
toNode: node7,
} as Edge,
];

jest.spyOn(edgeRepository, 'find').mockResolvedValue(expectedEdgeList);
const result = await service.findEdges();
expect(result).toEqual(expectedEdgeList);
expect(edgeRepository.find).toHaveBeenCalledTimes(1);
expect(edgeRepository.find).toHaveBeenCalledWith({
relations: ['fromNode', 'toNode'],
select: {
id: true,
fromNode: {
id: true,
},
toNode: {
id: true,
},
},
});
});

it('엣지가 없을 경우, 빈 배열을 던진다.', async () => {
jest.spyOn(edgeRepository, 'find').mockResolvedValue([]);
const result = await service.findEdges();
expect(result).toEqual([]);
});
});
});
Loading