자바스크립트_기초_3.5

HwiJeongLee·2021년 9월 3일
0

자바스크립트

목록 보기
22/28

테스트 자동화와 Mocha

테스트 자동화는 현업에서 광범위하게 사용되는 중요한 분야입니다.

테스트는 왜 해야할까요?

개발 중에 원하는 결과가 잘 나오고 있는지 코드 중간중간 콘솔 등을 이용하면서 확인하게 됩니다.
실제 실행 결과가 기대값과 다르다면 코드를 실행하여 그 결과를 다시 실행합니다.

이렇게 코드를 수동으로 재실행하면서 테스트를 하는 것은 상당히 불완전합니다.

개발자는 무언가를 만들 때 머릿속에 수많은 유스 케이스를 생각하며 코드를 작성합니다. 하지만 코드를 변경해야 할 때는 모든 유스 케이스를 다 고려하면서 코드를 수정하는 것은 거의 불가능에 가깝습니다.

👑테스팅 자동화는 테스트 코드가 실제 구현한 코드와 별개로 작성해야 하고 이를 이용하여 함수를 다양한 조건에서 실행해 볼 수 있는데, 이 때 실행 결과와 기대 결과를 비교합니다.

Behavior Driven Development (BDD)

BDD는 테스트, 문서, 예시를 한데 모아놓은 개념입니다.

거듭제곱 함수와 명세서

x를 n번 곱해주는 함수 pow(x,n) 함수를 구현하면서 BDD를 직접 적용해봅시다.

코드를 작성하기 전, 코드가 무슨 일을 하는지 상상해보고 자연어로 표현해봅시다. 이 자연어로 표현된 산출물을 BDD에서는 명세서 또는 스펙이라고 부릅니다. 아래는 명세서의 예시입니다.

describe("pow", function(){
	it("주어진 숫자의 n제곱 " , function(){
    	assert.equal(pow(2,3),8);
    });
});

스펙의 세 가지 주요 구성 요소
1. describe("title", function(){,,,})

구현하고자 하는 기능에 대해 설명해줍니다. 예로 위의 예시처럼 pow가 어떤 동작을 하는지 알려줍니다.
title에는 함수의 이름이 주로 들어갑니다.
it 블록들의 집합체이기도 합니다.

2. it("유스 케이스 설명", function(){,,,})

it의 첫 번째 인수에는 특정 유스 케이스에 대한 설명이 들어갑니다. 이 설명은 누구나 이해하기 쉬운 자연어로 적어줍니다.
두 번째 인수에는 유스 케이스 테스트 함수가 들어갑니다.

3. assert.equal(value1, value2)

기능을 제대로 구현했다면 해당 코드가 문제없이 실행됩니다.
assert는 위의 구현한 함수가 예상하는 대로 동작하는지 확인합니다. 만약 두 값이 다르다고 판단하면 에러를 반환합니다.

이런 명세서들은 실행이 가능하고, 실행 시 it 블록 안의 테스트가 실행됩니다.

개발 순서
1. 기본적인 테스트를 포함한 명세서 초안 작성
2. 명세서 초안을 바탕으로 코드 작성
3. 코드가 작동하는지 확인하기 위해 Mocha(아래 더 자세히 나옵니다.) 테스트 프레임워크를 사용해서 명세서 실행
이 때, 코드가 잘못 작성되었다면 에러가 출력되고 개발자들은 에러가 발생하지 않을 때까지 코드를 수정
4. 모든 테스드를 통과하는 코드 초안 완성
5. 명세서에 아직 고려하지 않았던 유스케이스를 추가
6. 3번부터 다시 코드 수정
7. 기능이 완성될 때까지 3~6번 반복

스펙 실행하기

스펙을 실행하기 위해서는 테스트 프레임워크가 필요합니다. 이때 3개의 라이브러리를 사용해서 테스드를 해봅시다. 이 라이브러리들은 브라우저나 서버 사이드 환경을 가리지 않고 사용할 수 있습니다.

1. Mocha
핵심 테스트 프레임워크로 describe, it 등과 같은 테스팅 함수와 테스트 실행 관련 주요 함수를 제공합니다.

2. Chai
다양한 assertion을 제공해 주는 라이브러리입니다. assert.equal이 가장 대표적인 메서드입니다.

3. Sinon
함수의 정보를 캐내는 데 사용하는 라이브러리로 내장 함수 등을 모방합니다. 이번 예시에서는 다루지 않습니다.

아래 예시는 pow의 스펙을 실행시켜봅니다.

  • <head> 테스트에 필요한 라이브러리와 스타일을 불러옵니다.
  • <script> 테스트할 함수의 코드가 들어갑니다.
  • 테스트 - describe("pow",...)를 외부 스크립트인 test.js에서 불러옵니다.
  • <html>요소인 <div id="mocha"> 은 Mocha 실행 결과를 출력합니다.
  • mocha.run() 테스트를 실행시킵니다.

현재는 pow에 관련된 아무런 코드도 없기에 테스트가 실패하고 브라우저에서는 다음과 같이 보여집니다.

이 때 pow 함수를 다음과 같이 구현해봅시다.

function pow (x,n){
	return 8; // 속임수로 다음과 같이 해봅시다.
 }

테스트를 assert.equal(pow(2,3),8) 코드를 사용하였기 때문에 위의 결과가 나왔지 다른 값들이면 모두 실패를 했을 것 입니다.

또 저희가 진짜 원하는 계산 과정이 아닌 속임수로 8을 리턴해도 참 값을 반환하므로 스펙을 개선할 필요가 있습니다.

스펙 개선하기

이제 assert 문을 하나 더 추가하여 다른 테스트 케이스들도 고려해봅시다. assert문을 추가하는 방법에는 다음과 같이 2가지 방법이 있습니다.

  1. 기존 it 블록에 assert 하나 더 추가하기
it("주어진 숫자의 n 제곱", function() {
    assert.equal(pow(2, 3), 8);
    assert.equal(pow(3, 4), 81);
  });
  1. 테스트를 하나 더 추가하기
  it("2를 세 번 곱하면 8입니다.", function() {
    assert.equal(pow(2, 3), 8);
  });

  it("3을 네 번 곱하면 81입니다.", function() {
    assert.equal(pow(3, 4), 81);
  });

assert에서 에러가 발생하면 it 블록은 즉시 종료됩니다.
만약 1번의 경우 중간에 한 케이스가 틀리면 아래의 assert문은 파악할 수 없게 됩니다.
그래서 2번의 방법처럼 it 블록을 하나 더 추가해서 테스트를 분리하면 더 많은 정보를 얻을 수 있게 됩니다.

좋은 스펙 작성을 위한 규칙
1. it 블록은 단위별로 분리해서 작성하기
2. 테스트 하나에선 한가지만 확인하기

새로 바꾼 assert를 테스트하면 위와 같은 결과가 나옵니다.
두 번째 테스트가 실패하였는데 이는 pow 함수가 항상 8을 반환하는 함수이므로 실패가 당연합니다.

이제는 코드를 개선해야 할 것 같습니다.

코드 개선하기

funxtion pow (x,n){
	var result = 1;
    
    for (int i = 0;i < n; i++){
    	result  = result * x; // x를 n번 곱하는 함수
    }
    return result
}

스펙도 하나하나 작성하지 않고 for문을 이용해서 작성해봅시다.

describe("pow", function() {
	
    function makeTest(x){
    	var expected = x*x*x;
        it(`${x}을/를 세 번 곱하면 ${expected}입니다.`,function() {
      assert.equal(pow(x, 3), expected);
    });
  }
  
  for (let i = 1; i<=5;i++){
  	makeTest(x);
  }
  
});  

결과는 위와 같고 드디어 pow 함수를 올바르게 구현할 거 같습니다.

중첩 describe

바로 위의 스펙을 중첨 describe를 사용하여 그룹화할 수 있습니다.

이렇게 해도 위와 같은 결과가 출력됩니다.

before 함수 vs after함수
before 함수는 테스트가 실행되기 전에 실행
after 함수는 테스트가 실행된 후에 실핸

beforeEach 함수 vs afterEach 함수
beforeEach 함수는 매 단일 테스트 it이 실행되기 전에 실행
afterEach 함수는 매 단일 테스트 it이 실행된 후에 실행

스펙 확장하기

사실 pow(x,n)의 경우 n은 양의 정수여야만 합니다.

자바스크립트에서는 수학 관련 연산을 수행하다가 에러가 발생하면 NaN을 반환하므로 n이 조건에 맞지 않다면 마찬가지로 NaN을 반환합니다.

이 때 n이 조건에 맞지 않다면 NaN을 수행하는지를 확인하는 코드를 describe에 추가하여봅시다.

결과는 다음과 같습니다.

pow함수를 구현할 때 n의 범위를 지정해주지 않았으므로 이 테스트가 실패하는 것은 당연한 결과입니다.

위의 테스트까지 통과하기 위해서는 pow함수를 개선시켜봅시다.

funxtion pow (x,n){
	// n이 음수라면..
	if(n < 0) return NaN;
    // n이 정수라면.. + 음수가 아니라면     
    if(Math.round(n) != n) return NaN ;
    
    var result = 1;
    
    for (int i = 0;i < n; i++){
    	result  = result * x; // x를 n번 곱하는 함수
    }
    return result
}

이렇게되면 모든 테스트를 다 통과하게됩니다.

BDD를 사용하는 핵심은 실패할 수 밖에 없는 테스트를 추가하고 테스트를 통과할 수 있게 코드를 계속 개선해나가는 것입니다.

참고) 다양한 assertion

  • assert.equal(v1,v2) v1 == v2 동등성을 확인
  • assert.strictEqual(v1,v2) v1 === v2 일치성을 확인
  • assert.notEqual(v1,v2),assert.notStrictEqual(v1,v2) 비 동등성, 비 일치성을 확인합니다.
  • assert.isTrue(v1) v1가 true인지 확인합니다.
  • assert.isFalse(v1) v1가 fasle인지 확인합니다.
  • assert.isNaN(v1) v1이 NaN인지 확인합니다.

출처

자바스크립트_기초 관련 게시글은 모던 JAVAScript 튜토리얼 사이트를 보고 작성합니다.

profile
초보 개발자의 개발 공간

0개의 댓글