Skip to content

1114(화) BE 회의록

박재하 edited this page Dec 12, 2023 · 2 revisions

오늘 할 일

  • 12시부터 페어 프로그래밍
    • 테스트 코드 작성
    • board, auth CRUD 구현
  • 개발 기록 정리
    • ncp 서버 생성 과정
    • docker 이미지 생성 과정
    • TDD 과정
  • 9시에 멘토님과 멘토링

오늘 한 일

개발 환경 세팅

이번에 팀 레포 프로젝트 폴더를 완전히 갈아 엎으면서 fork로 떠온 개인 레포에서 다시 upstream(팀 레포)를 fetch, rebase할 일이 생겼다.

사실 fork해온 저장소를 지우고 다시 fork를 했으면 쉽게 세팅이 됐겠지만 git 연습도 해볼 겸 그대로 fetch, rebase를 진행하였다.

  1. fork repo git clone

https://user-images.githubusercontent.com/138586629/282657313-8f8e50e5-f268-423b-ad39-bc1e56b8e9d0.png

  1. remote add upstream

https://user-images.githubusercontent.com/138586629/282657322-fe700b1f-a154-499b-a95e-7242d052e405.png

  1. fetch, reset upstream main

https://user-images.githubusercontent.com/138586629/282657325-666438c6-21f5-4969-9c7e-beccd83ae753.png

  1. git log

https://user-images.githubusercontent.com/138586629/282657331-a3ae2f98-5658-4831-b6eb-617f7eded392.png

  1. git push -f origin main ( fork해온 개인 repo에 push)

https://user-images.githubusercontent.com/138586629/282657335-74d05e0a-49f2-4d18-b50a-be887dd14323.png

  1. fetch, rebase be-develop (upstream의 be-develop 브랜치 fetch, rebase)

https://user-images.githubusercontent.com/138586629/282657337-7bf89c75-2768-4cec-9c24-bd121e800e4c.png

  1. git log 확인

https://user-images.githubusercontent.com/138586629/282657331-a3ae2f98-5658-4831-b6eb-617f7eded392.png

  1. rebase be-develop with upstream main

https://user-images.githubusercontent.com/138586629/282657342-b1cbe5f4-a06e-46b8-b71c-12b4f20d490d.png

  1. push origin be-develop

https://user-images.githubusercontent.com/138586629/282658989-6a601a22-4e71-4dc2-92e4-8e825519727c.png

  1. final git graph

https://user-images.githubusercontent.com/138586629/282657344-610a8b82-e3d4-4cfc-9588-e65ca5a22663.png

CRUD Generator를 이용한 board, auth 모듈 생성 - 재하

프로젝트 설정 (yarn berry)

현재 프로젝트 be-develop 브랜치에 대한 local PC로의 pull을 완료한 후 yarn install을 해준다.

yarn install
스크린샷 2023-11-14 오후 1 35 33

VSCode의 경우는 아래와 같이 @yarnpkg/sdks, vscode를 dlx로 세팅해줘야 함.

yarn dls @yarnpkg/sdks vscode
스크린샷 2023-11-14 오후 1 15 01

TypeScript 버전을 Workspace 버전으로 할 것인지 묻는 알럿창이 뜨면 허용하고, 그러면 관련된 vscode 설정이 프로젝트 루트에 추가됨.

스크린샷 2023-11-14 오후 2 00 29
// settings.json
{
	"search.exclude": {
		"**/.yarn": true,
		"**/.pnp.*": true
	},
	"prettier.prettierPath": ".yarn/sdks/prettier/index.cjs",
	"typescript.tsdk": ".yarn/sdks/typescript/lib",
	"typescript.enablePromptUseWorkspaceTsdk": true
}

gitignore해주자.

nest g resource를 활용해 user, board 모듈/컨트롤러/서비스 및 CRUD 구현

nest g resource

nest g module, controller, service가 아닌 nest g resource를 활용해 한번에 생성해주자. 이 기능을 활용하면 CRUD Generator로 CRUD 메소드까지 같이 생성해준다. (학습메모 2)

yarn workspace server nest g resource

프로젝트 루트 폴더는 위 명령을 통해 만들어줄 수 있다.

스크린샷 2023-11-14 오후 1 08 55

같은 방식으로 auth, board 모두 생성해줬다.

jest test파일

자동 생성된 모든 test 파일을 test 폴더에 계층(모듈)별로 폴더를 만들어 옮긴 후, jest 설정을 바꾸어 이를 인식할 수 있게 변경해주자.

// package.json
{
  ...
	"jest": {
		...
		"rootDir": "test",
		"testRegex": ".*\\.(e2e-)?spec\\.ts$",
		...
	}
}

rootDir을 src에서 test로, testRegex는 e2e-spec.ts도 잡아줄 수 있도록 .*\\.spec\\.ts$에서 .*\\.(e2e-)?spec\\.ts$로 변경해준다.

// package.json
{
	...
	"jest": {
		...
		"verbose": true,
		"collectCoverage": true,
		...
	}
}

추가로 상세 describe와 coverage까지 출력할 수 있도록 verbosecollectCoveragetrue로 설정해주는 구문을 package.json에 추가해준다.

확인해보자.

yarn test

루트 디렉토리에서 위에 해당하는 명령은

yarn workspace server test
스크린샷 2023-11-14 오후 1 55 14

원래 이랬던 게

스크린샷 2023-11-14 오후 2 39 30

아? rootDir이 test라서 src 내의 파일들을 못잡아줌..

추가적인 설정이 필요하겠다.

고군분투 끝에 collectCoverageFrom 설정에서 src만 잡아주도록 수정해줄 수 있었다.

{
	...
	"jest": {
		...
		"rootDir": ".",
		...
		"collectCoverageFrom": [
			"<rootDir>/src/**/*.(t|j)s"
		],
		"coverageDirectory": "./coverage",
		...
	}
}
스크린샷 2023-11-14 오후 2 37 25

이렇게 이쁘게 나온다! coverage는 앞으로 열심히 올려보자.

최종 package.json은 다음과 같다.

// package.json
{
	...
	"jest": {
		"moduleFileExtensions": [
			"js",
			"json",
			"ts"
		],
		"rootDir": ".",
		"testRegex": ".*\\.(e2e-)?spec\\.ts$",
		"transform": {
			"^.+\\.(t|j)s$": "ts-jest"
		},
		"verbose": true,
		"collectCoverage": true,
		"collectCoverageFrom": [
			"<rootDir>/src/**/*.(t|j)s"
		],
		"coverageDirectory": "./coverage",
		"testEnvironment": "node"
	}
}

실패하는 Unit Test Code 작성

학습메모 3dm

Auth Controller

// auth.controller.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { AuthController } from '../../src/auth/auth.controller';
import { AuthService } from '../../src/auth/auth.service';

describe('AuthController', () => {
	let controller: AuthController;

	beforeEach(async () => {
		const module: TestingModule = await Test.createTestingModule({
			controllers: [AuthController],
			providers: [AuthService],
		}).compile();

		controller = module.get<AuthController>(AuthController);
	});

	it('should be defined', () => {
		expect(controller).toBeDefined();
	});
});

기본 생성되는 코드는 위와 같다. CRUD 메소드에 대한 테스트 코드를 copilot의 도움을 받아 추가해봤다.

// auth.controller.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { AuthController } from '../../src/auth/auth.controller';
import { AuthService } from '../../src/auth/auth.service';

describe('AuthController', () => {
	let controller: AuthController;
	let service: AuthService;

	beforeEach(async () => {
		const module: TestingModule = await Test.createTestingModule({
			controllers: [AuthController],
			providers: [AuthService],
		}).compile();

		controller = module.get<AuthController>(AuthController);
		service = module.get<AuthService>(AuthService);
	});

	it('should be defined', () => {
		expect(controller).toBeDefined();
	});

	describe('findAll', () => {
		it('should be defined', () => {
			expect(controller.findAll).toBeDefined();
		});

		it('should return an array of auth', async () => {
			const result = ['test'];
			jest.spyOn(service, 'findAll').mockImplementation((): any => result);

			expect(await controller.findAll()).toBe(result);
		});
	});

	describe('findOne', () => {
		it('should be defined', () => {
			expect(controller.findOne).toBeDefined();
		});

		it('should return an auth', async () => {
			const result = 'test';
			jest.spyOn(service, 'findOne').mockImplementation((): any => result);

			expect(await controller.findOne('1')).toBe(result);
		});
	});

	describe('create', () => {
		it('should be defined', () => {
			expect(controller.create).toBeDefined();
		});

		it('should return an auth', async () => {
			const result = 'test';

			jest.spyOn(service, 'create').mockImplementationOnce((): any => result);

			expect(await controller.create({})).toMatchObject(result);
		});
	});

	describe('update', () => {
		it('should be defined', () => {
			expect(controller.update).toBeDefined();
		});

		it('should return an auth', async () => {
			const result = 'test';
			jest.spyOn(service, 'update').mockImplementation((): any => result);

			expect(await controller.update('1', {})).toBe(result);
		});
	});

	describe('remove', () => {
		it('should be defined', () => {
			expect(controller.remove).toBeDefined();
		});
	});
});

여기서 mocking되지 않은 service를 또 테스트해봐야 되지 않을까 하는 의문이 생겨, 열띤 토론끝에 오늘 백엔드 멘토님과의 멘토링 시간에 질문을 드려보기로 했다. TDD는 대체 어떤 방식으로 하는 걸까? 지금 Entity 속성이 없는데 이건 어떤 순서로 개발해야 하는거지?

Entity 테스트 코드 작성 -> Entity 구현 -> Controller 테스트 코드 작성 -> Controller 구현 -> Service 테스트 코드 작성 -> Service 구현 -> Repository 테스트 코드 작성

이런 순서가 맞는건지, Repository는 이미 정의된 메소드를 쓰는데 또 이게 실제로 들어가는지 확인하려면 어떤 방식으로 테스트를 해야 하는지가 막막했다.

// 예를 들면 이런식으로 해야하는게 아닐까?

describe('create', () => {
	it('should be defined', () => {
		expect(controller.create).toBeDefined();
	});

	it('should return an auth (mock service)', async () => {
		const result = 'test';

		jest.spyOn(service, 'create').mockImplementationOnce((): any => result);

		expect(await controller.create({})).toMatchObject(result);
	});

	it('should return an auth (real)', async () => {
		// given
		const user = 'test'; // TODO : 제대로된 User 인스턴스가 들어가야 함.

		// when
		const result: any = await controller.create(user);

		// then
		expect(result).toBeInstanceOf(User);
		expect(result).toMatchObject(user);
	});

	it('should assign new id (real)', async () => {
		// given
		const user = 'test'; // TODO : 제대로된 User 인스턴스가 들어가야 함.

		// when
		const result: any = await controller.create(user);

		expect(result).toHaveProperty('id');
		expect(result.id).toBeInstanceOf(Number);
	});
});

그래서 여기까지 줄이고 TDD와 동시성 제어와 관련해 질문지를 꼼꼼히 작성하고 멘토링 후 TDD를 계속 진행해보기로 했다!

참고삼아 Repository를 mocking한 Service 유닛테스트 코드 예시까지만 남기고 오늘의 개발기록을 마친다.

// board.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { BoardService } from './board.service';
import { Board } from './entities/board.entity';

describe('BoardService', () => {
	let service: BoardService;
	let repository: Repository<Board>;

	beforeEach(async () => {
		const module: TestingModule = await Test.createTestingModule({
			providers: [
				BoardService,
				{
					provide: getRepositoryToken(Board),
					useClass: Repository,
				},
			],
		}).compile();

		service = module.get<BoardService>(BoardService);
		repository = module.get<Repository<Board>>(getRepositoryToken(Board));
	});

	it('should be defined', () => {
		expect(service).toBeDefined();
	});

	describe('findAll', () => {
		it('should be defined', () => {
			expect(service.findAll).toBeDefined();
		});
		it('should return an array of boards', async () => {
			const board = new Board();
			board.id = 1;
			board.title = 'test';
			board.content = 'test';
			board.image = null;
			board.star_style = 'test';
			board.star_position = 'POINT(0, 0, 0)';
			board.author = 'test';
			board.created_at = new Date();
			board.modified_at = new Date();
			const boards = [board];

			jest.spyOn(repository, 'find').mockImplementation(async () => boards);

			expect(await service.findAll()).toBe(boards);
		});
	});
});

학습메모

  1. [GIT] Conflict(충돌) 났을 때 강제로 Pull 하기.
  2. NestJS CRUD Generator
  3. NestJS, TDD로 개발하기
  4. NestJS Mocking하기
  5. Repository 테스트하기

CRUD Generator를 이용한 board, auth 모듈 생성 - 준섭

  • 준섭

    1. auth resource 추가 nest g resource로 auth 리소스 추가

      1

      근데 이렇게 하고 git status를 쳐보니까

      2

      이런 식으로 .yarn 폴더 안에 unplugged 폴더 수정이 많이 일어났다.

      그러나 같이 페어 프로그래밍을 하고 있는 재하님은 unplugged 폴더 수정이 일어나지 않았다.

      혹시 몰라서 nest 버전도 맞추고, yarn install도 같이 해보고 다시 nest g reousrce를 해보았지만 결과는 역시 달랐다.

      이유가 뭐지?

      • 해결 다시 처음 상태로 git reset --hard로 돌아감 그 다음 yarn workspace server nest g resource로 auth 모듈 생성 이 상태로 다시 루트 폴더에서 yarn install을 하니 재하님과 git status도 똑같아지고 서버 실행도 잘 되었다. 내가 package/server 폴더까지 들어가서 yarn install을 한 게 잘못이었던 듯 하다
    2. board resource 추가

      위와 같은 방법으로 추가 완료

테스트 코드 작성 - 준섭

  • 준섭

    테스트 환경 설정

    1. .spec 테스트 파일들 test 폴더로 이동

      3

      그러고 yarn workspace server test를 해보려고 하니

      4

      다음과 같이 test 파일들을 찾을 수 없다는 안내가 뜸

      그 원인을 알아보니 package.json에 jest 설정 중 root 폴더 패스 때문이었음.

      5

      package.json의 root 설정이 원래 "src"로 되어있었던 것을 위와 같이 "test"로 수정

      그 후 testRegex 설정도 e2e test들은 그냥 .spec이 아닌 .e2e-spec으로 되어있기 때문에 수정해주었음.

      이렇게 하고 다시 yarn workspace server test를 해보니 잘 됨!

      6

    2. verbose, collectCoverage 설정 추가

      그리고 test 실행 시 좀 더 자세한 설명을 추가하는 verbose 옵션과 만든 기능들을 테스트 코드로 얼마나 커버하는지를 알려주는 collectCoverage 옵션을 추가해 주었음.

      처음에는 jest.config.json 생성해서 설정을 추가하고 다시 test를 해보았는데, 다음과 같은 오류가 뜸

      7

      nest 프로젝트 자체에서 저렇게 따로 config.json을 생성해주는 것이 아니라 package.json의 jest 옵션에서 관리를 해주는 것 같았음.

      8

      위와 같이 "verbose" 옵션과 "collecCoverage" 옵션을 추가

      9

      테스트가 예쁘게 잘 출력되는 줄 알았으나 coverage 부분이 비어있음..

      10

      위와 같이 rootDir을 "."으로 수정하고 collectCoverageFrom으로 커버리지 수집 폴더를 지정해 줌.

      그러니 이제야 드디어 테스트가 완벽히 예쁘게 실행 됨^^

      11

    • 참고

    [https://www.inflearn.com/questions/14613/no-tests-found-exiting-with-code-1-에러](https://www.inflearn.com/questions/14613/no-tests-found-exiting-with-code-1-%EC%97%90%EB%9F%AC)

    https://www.daleseo.com/jest-coverage/

소개

규칙

학습 기록

[공통] 개발 기록

[재하] 개발 기록

[준섭] 개발 기록

회의록

스크럼 기록

팀 회고

개인 회고

멘토링 일지

Clone this wiki locally