Test Driven Development
소프트웨어 개발 방법론 중 하나입니다. 개발자가 실제 코드를 작성하기 전에 자동화된 테스트를 작성하는 방식입니다.
테스트 코드를 먼저 작성하고, 작성한 테스트코드에 맞는 소프트웨어 코드를 짜는 방식을 반복하면서 새로운 기능을 추가하거나 기존 코드를 개선합니다.
TDD를 하는 이유는 코드를 철저하게 테스트하고 고품질의 코드를 유지하는 것입니다. 개발자가 먼저 테스트를 작성함으로써 개발 프로세스 초기에 문제를 식별하고 해결할 수 있으며, 새로운 기능을 추가하거나 기존 코드를 변경함에 따라 코드베이스가 안정적인 상태를 유지할 수 있도록 합니다.
장점
- 코드 품질 향상: TDD를 적용하면 개발자는 코드를 작성하기 전에 미리 테스트를 작성하므로 코드 품질이 향상됩니다. 개발자는 테스트를 통과하기 위해 더 간결하고 명확한 코드를 작성하게 되어 유지보수가 더 쉬워집니다.
- 버그 감소: TDD를 적용하면 개발자가 코드를 작성하는 도중에 버그를 미리 발견하고 수정할 수 있습니다. 또한 코드가 변경될 때마다 테스트를 실행하므로 코드 변경으로 인한 버그가 줄어듭니다.
- 빠른 피드백: TDD를 적용하면 코드를 작성한 후 테스트를 실행하여 즉각적인 피드백을 받을 수 있습니다. 이를 통해 개발자는 문제를 신속하게 해결할 수 있습니다.
- 코드 문서화: TDD를 적용하면 개발자가 작성한 테스트는 코드의 문서화 역할을 합니다. 이를 통해 코드를 이해하고 수정하는 데 시간을 절약할 수 있습니다.
단점
- 추가 작업 필요: TDD를 적용하면 코드를 작성하기 전에 먼저 테스트를 작성해야 하므로 추가 작업이 필요합니다. 이는 개발 시간을 늘리고 개발 비용을 증가시킬 수 있습니다.
- 추가 학습 : TDD는 새로운 개발 방법론이기 때문에 개발자들이 새로운 개념과 도구를 배워야 합니다. 이에 따라 TDD를 적용하기 위해서는 학습이 필요할 수 있습니다.
- 테스트 작성 어려움: 테스트를 작성하기 위해서는 테스트 대상을 이해하고 테스트 케이스를 작성해야 합니다. 이는 경우에 따라 어려울 수 있으며, 개발자가 테스트를 작성하는 데 능숙해지기까지 시간이 필요할 수 있습니다.
직접 사용 후기
TDD를 이용해서 간단한 API를 제작해 봤다.
기존에 API를 작성하는 것과 다른 것은 위에서 설명드렸듯이 테스트코드를 먼저 작성하고 그 다음에 소프트웨어 코드를 작성하는 것이다.
모카, supertest, should모듈을 이용하여 진행하였습니다.
코드 하나 정도만 소개해 볼게요(연습용이기 때문에 코드가 지저분 할 수 있습니다 ㅎㅎ)
POST User TEST CODE
describe('POST /users', () => {
describe('성공시', () => {
let name = 'hosose';
let body;
before((done) => {
request(app)
.post('/users')
.send({ name })
.expect(201)
.end((err, res) => {
body = res.body;
done();
});
});
it('생성된 유저 객체 반환', () => {
body.should.have.property('id');
});
it('입력한 name 반환', () => {
body.should.have.property('name', name);
});
});
describe('실패시', () => {
it('name 파라미터 누락 400 반환', (done) => {
request(app).post('/users').send({}).expect(400).end(done);
});
it('name 파라미터가 영어가 아니면 400 반환', (done) => {
let name = '호소세';
request(app).post('/users').send({ name }).expect(400).end(done);
});
it('입력한 name이 중복이면 409 반환', (done) => {
let name = 'tony'; //es6문법
request(app).post('/users').send({ name }).expect(409).end(done);
});
});
});
POST User
const postUser = function (req, res) {
const name = req.body.name;
//이름이 영어인지 정규표현식으로 확인
const eng = /^[a-zA-Z]*$/;
if (!name || !eng.test(name)) return res.status(400).end();
//user테이블에서 유저의 이름이 중복되는지 확인
const overlapUser = users.filter((user) => user.name === name)[0];
if (overlapUser) return res.status(409).end();
//새로운 user의 아이디는 현재 시간으로 설정
const id = Date.now();
const user = { id, name };
users.push(user);
res.status(201).json(user);
};
먼저 테스트코드를 작성하고 하나하나 조건에 맞게 수정해주면 됩니다.
개발 중 오류
이제 부터 개발 중 오류를 전부 작성하고 해결하는 것을 작성해 보려고 합니다.
1. Cannot set headers after they are sent to the client at new NodeError
-> http요청안에 response가 두개 들어가서 조건 문 안에 return 값을 정확히 작성하면 오류 발생하지 않음(너무도 당연하지만 실수했기에..)
if (Number.isNaN(limit) || Number.isNaN(offset)) {
return res.status(400).end();
}
res.json(users.slice(offset - 1, limit));
2. 테스트 실행하고 서버가 안꺼지는 오류 해결
-> test 실행문 뒤에 -exit 작성
"scripts": {
"test": "NODE_ENV=test mocha api/user/user.spec.js -exit",
"start": "nodemon --watch ./ --exec node www.js"
},
3. nodemon으로 index파일 말고 다른 것으로 서버를 열고 싶으면
-> script에 "nodemon --watch ./ --exec node bin/www.js" 라고 작성 하면 된다. 또는 아래와 같은 파일 생성
## ./nodemon.json
{
"watch": ["./"],
"exec": "node server.js",
"ext": "js json yaml",
"ignore" : ["./logs/"]
}
watch : 서버 재시작을 위한 변경 감지 경로 / exec : nodemon 수행 명령 / ext : 변경 감지할 확장자 / ignore: 변경 감지 제외
소감
테스트 코드를 먼저 작성하게 되면 제가 처음에 생각했던 것 뿐만 아니라 더 많은 에러에 대한 생각을 하게 됩니다. 만약에 서버를 올리고 사용자들이 사용하다가 에러가 생기면 난감하기 때문에 에러를 미연에 방지하는 쪽이 좋아보인다고 생각합니다.
프로젝트 때 작성한 코드들을 TDD방식으로 리팩토링 해보면서 복습해보겠습니다.
'코딩 개발' 카테고리의 다른 글
Agile & Waterfall 개발 방식 (0) | 2023.04.02 |
---|---|
다이나믹 프로그래밍 (2) | 2023.03.04 |
IT 5분 잡학 사전 EP39~EP45 (0) | 2023.03.02 |
IT 5분 잡학 사전 EP30~EP34 (0) | 2023.02.27 |
코딩테스트 - 대충 만든 자판 (0) | 2023.02.25 |