기본 콘텐츠로 건너뛰기

[node.js] 단위(TDD) 및 행동(BDD) 테스트

TDD란?
 - Test-driven development의약자로 
    쉽게 설명을 하면 개발을 하게되면 수많은 함수들을 생성을 하게 된다. 근데 이 함수가 정상적인 값을 되돌려주는지 확인하는 방법이           TDD이다. TDD는 테스트 자체에 집중하여 개발을 한다.

BDD란?
 - Behaviour-Driven Development의 약자로 TDD와 비슷하지만 좀더 자연어에 가깝게 테스트 케이스를 작성한다. 대표적인 것이 바로 User      Story기법이다. 

node.js에서는 mocha라는 프레임 워크를 이용한다.

npm install -G mocha
G는 글로벌(global)을 의미한다

*tip 
 - 보통 supervisor, gulp, mocha와 같이 명령어로 사용 되는 친구들은 -g를 하여 글로벌로 해주는 것이 정신건강에 좋다.


TDD와 BDD를 따로 구분을 짓지는 않겠다.(또한 한두개의 메서드만 언급할 뿐 구조를 중심적으로 언급을 하겠다)
메서드를 다루기에는 양이 너무 많다 ㅎㅎㅎㅎㅎ


1
2
3
4
5
6
7
8
9
10
11
12
13
14
describe('frame',function(){
    it('test1',function(){
    });
    it('test2',function(){
    });
    it('test3',function(){
    });
});
cs

실행결과.

콘솔창에 frame과 test1~3까지 찍혔다.

it이 각 단위이다.
(it과 if를 헤깔리지 말것!)

여기서 assert라는 모듈을 추가하여 test를 할 수 있다.
(TDD에서는 assert를 BDD에서는 expect.js를 추가해주면 된다.)

그럼 코드가 어떤식으로 작동을 하는지 좀더 테스트를 해보자.


1
2
3
4
5
6
7
8
9
10
11
12
describe('frame',function(){
    it('test1',function(){
        console.log('It Test1');
    });
    it('test2',function(){
        console.log('It Test1');
    });
    it('test3',function(){
        console.log('It Test2');
    });
});
cs

실행결과.

it내부가 먼저 찍히고 첫번째 인자인 test1~3이 찍힌다.

이제 assert라는 놈을 이용해보자.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
var assert = require('assert');
describe('frame',function(){
    it('test1',function(){
        assert.equal('aaa','aa',"asdasd");
    });
    it('test2',function(){
        console.log('It Test1');
    });
    it('test3',function(){
        console.log('It Test2');
    });
});
cs

실행결과.




 mocha app을 해주니 1)test1쪽에서 문제가 발생하였다.
it('test1',function(){
        assert.equal('aaa','aa',"asdasd");
    });
해당 후분에서 문제가 발생하엿다.

assert.equal()요놈은 첫번째 인자와 두번째 인자가 같은지를 묻는다. 
다르기 때문에 에러를 띄운다. 여기서는 에러를 띄워도 중단 되지 않고 3번째 인자를 출력한다.

1) frame test1: 
 AsserionError : asdasd가 그 부분이다.


여러개의 단위를 테스트를 하기 전(before), 후(after)에 특정 단위를 거쳐야 하는 경우가 있다.

이럴 경우는 before, after를 주면 된다. 또한 한번만 할 건지 매 단위마다 할던지에 따가 beforeEach, afterEach까지 추가적으로 사용하기도 한다.
이런 놈들을 후크라고 한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
before(function(){
    console.log('before');
});
describe('frame',function(){
    beforeEach(function(){
        console.log('beforeEach');
    })
    it('test1',function(){
            console.log('t1');
    });
    it('test2',function(){
            console.log('t2');
    });
    it('test3',function(){
            console.log('t3');
    });
});
cs

실행결과.


describe가 실행 되기전에 가장 가까이 있는 before를 실행한다(after는 그 반대다. describe가 실행 되고 after문이 실행 된다.)
beforeEach는 it문이 실행 되기 전에 실행되는 부분이다.(afterEach도 그 반대이다. it이 실행 된후 afterEach문이 실행된다)


테스트에 필요한 모듈을 만들어 보도록 하겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function TestModules(n) {
  var  n = Math.floor(n);
  if (n >= 2) {
    return n;
  } else {
    return 1;
  }
}
module.exports.TestModules = TestModules;
cs
index.js파일

함수를 만들어 module로 외부에서 접근이 가능하다.

test를 하는 코드를 다음과 같이 수정을 한다.

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 var testmodules = require('./index').TestModules;
var assert = require('assert');
before(function(){
    console.log('before');
});
describe('frame',function(){
    it('test1',function(){
        assert.equal(1,testmodules(1));
    });
    it('test2',function(){
        assert.equal(1,testmodules(2));
    });
    it('test3',function(){
        assert.equal(3,testmodules(3));
    });
    it('test2',function(){
        assert.equal(0,testmodules(0));
    });
});
cs
2번 라인에서 index를 모듈로 추출하고 객체가 됬기때문에 module을 사용했기 때문에 내부 함수가 접근이 된다.
TestModules를 접근하여 마치 하나의 파일에서 불러서 쓰는 효과가..ㅋㅋㅋ

mocha app 실행결과



2개는 성공 2개는 실패 이부분은 코드를 보면 왜 성공과 실패 했는지 알 수 있다

또한 실패 유무 뿐만 아니라 실패한 이유까지 보여진다.

에러를 띄어줄떄 어느 frame과 case위치까지 띄어주기 때문에 훨씬 효율 적으로 테스팅이 가능하다.

추가적으로 describe는 .only나 .skip을 특정 케이스만 실행하거나 특정 케이스를 건너띄는 베타적 적용이 가능하다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var assert = require('assert');
before(function(){
    console.log('before');
});
describe('frame1',function(){
    it('should respond to Get'function(){
        
    });
});
describe.skip('frame2',function(){
    it('should respond to Get'function() {
    })
});
cs

.skip()을 사용했을 떄의 실행결과

skip을 하는 부분은 청녹색으로 뜨나보다 ㅋㅋㅋㅋㅋㅋ

.only()을 사용했을 떄의 실행결과


assert를 chai를 이용하면 좀더 많은 메소드를 사용할 수 있다.
var assert = require('chai').assert;
추가적으로 좀더 많은 검사가 가능
assert : 표현식이 거짓이면 에러를 발생
assert.fail(actual, expected, [emessage],[operator]) : actual, expected 및 operator를 이용한 비교 결과에 따라서 에러인지를 나타냄
assert.ok(object,[message]) : 객체가 참이면 에러를 발생
assert.notOk(object,[message]) : 객체가 거짓이면 에러를 발생
assert.equal(actual,expected,[message]) : actual과 expected가 같지 않으면 에러
assert.notEqual(actual,expected,[message]) : actual과 expected가 같으면 에러
assert.stricEqual(actual,expected,[message]) " 객체가 엄격히 동일하지 않을 때(===) 에러 발생

공식문서(http://chaijs.com/api/assert/)를 참조하면 더 많은 메소드를 접할 수 있다.


BDD는 위와 같은 구조를 지닌다.
var expect = require('expect.js');
assert가 아닌 expect.js를 추가한다.

BDD는 TDD보다 좀더 직관적이다.

1
expect.(array[n]).equal(array[m]); === assert.equal(array[n],array[m]);
cs
같은 의미가 된다. 하지만 좀더 직관적으로 보인다.

추가적으로 expect.js가 가지고 있는 메소드를 더 살펴보면
ok : 참인지 확인
true : 객체가 참인지 확인 
to.be : 두 메소드 간 링크 제공
to : 두 메소드 간 링크 제공
not : expect(false).not.to.be(true) 처럼 부정을 내포하지만 연결 관를 가짐
a/an : 타입 체크(배열에도 적용 가능)
inclue/contain : 매열 또는 스트링이 엘리먼트를 포함하는지 체크
below/above : 상위와 하위의 한계정 체크

댓글

이 블로그의 인기 게시물

[kali linux] sqlmap - post요청 injection 시도

아래 내용은 직접 테스트 서버를 구축하여 테스트 함을 알립니다.  실 서버에 사용하여 얻는 불이익에는 책임을 지지 않음을 알립니다. sqlmap을 이용하여 get요청이 아닌 post요청에 대해서 injection공격을 시도하자. 뚀한 다양한 플래그를 이용하여 DB 취약점 테스트를 진행을 해보려고 한다. 서버  OS : windows 7 64bit Web server : X Server engine : node.js Framework : expresss Use modules : mysql Address : 172.30.1.30 Open port : 6000번 공격자 OS : kali linux 64bit use tools : sqlmap Address : 172.30.1.57 우선 서버측 부터  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 var  express  =  require( 'express' ); var  app  =  express(); var  mysql  =  require( 'mysql' ); var  ccc  =  mysql.createConnection({     host: '127.0.0.1' ,     user: 'root' ,     pos...

[git] git log 확인하기

git log를 통해서 커밋 이력과 해당 커밋에서 어떤 작업이 있었는지에 대해 조회를 할 수 있다. 우선 git에서의 주요 명령어부터 알아보겠다. $ git push [branch name] $ git pull [branch name] 여기서 branch name은 로컬일 경우 해당 브런치 이름만 적으면 되지만 깃허브 원격 저장소로 연결을 원할 경우는 해당 브런치 이름 앞에 꼭 origin을 붙이도록 한다. $ git brnch [branch name] $ git checkout [branch name] branch일경우 해당 브런치를 생성을 한다. 여기서 현재의 브런치를 기준으로 브런치를 따는것이다. checkout은 브런치를 바꾸는 것이다.(HEAD~[숫자]를 이용하면 해당 커밋으로 움직일수 있다.. 아니면 해당 커밋 번호를 통해 직접 옮기는것도 가능하다.) -> 해당 커밋으로 옮기는 것일뿐 실질적으로 바뀌는 것은 없다. 해당 커밋으로 완전히 되돌리려면 reset이라는 명령어를 써야한다. 처음 checkout을 쓰면 매우 신기하게 느껴진다. 막 폴더가 생겼다가 지워졌다가 ㅋㅋㅋㅋㅋ  master 브런치에서는 ht.html파일이 존재하지만 a브런치에서는 존재하지않는다. checkout 으로 변경을 하면 D 로 명시를 해준다.  $ git log 해당 브런치의 커밋 내역을 보여준다. a 브런치의 커밋 내역들이다. (머지 테스트를 하느라 커밋 내용이 거의 비슷하다 ㅋㅋ) master 브런치의 커밋 내역들이다. 커밋 번호, 사용자, 날짜, 내용순으로 등장을 한다. 이건 단순히 지금까지의 내역을 훑어보기 좋다. 좀더 세밀한 내용을 봐보자. $ git log --stat --stat을 붙이면 기존의 로그에서 간략하게...

[git] pull을 하여 최신코드를 내려받자

보면 먼가 로고가 다르게 뜨는것을 확인을 할 수가있다. C:\Users\mung\Desktop\etc\study\python-gene>git checkout remotes/origin/master Note: checking out 'remotes/origin/master'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example:   git checkout -b HEAD is now at 29e282a... fetch test C:\Users\mung\Desktop\etc\study\python-gene>git branch * (HEAD detached at origin/master)   master   test1   test2 깃이 잘 쓰면 참 좋은놈인데 어지간히 쓰기가 까다롭다. 처음에 깃을 푸시 성공하는데만 한달정도 걸렸던걸로 기억이 난다.. ㅋㅋㅋ 여담으로  깃 프로필을 가면 아래사진 처럼 보인다. 기여도에 따라서 초록색으로 작은 박스가 채워지는데 저걸 잔디라고 표현을 한다고 합니다 ㅎ 저 사진은 제 깃 기여도 사진입니당 ㅋㅋㅋㅋ 다시 본론으로 돌아와서 ㅋㅋ pull을 하면...