회고록 블로그

[공부 필기] JavaScript 문법 공부 16일차 (3) 본문

2. 프로그래밍 언어 공부/JavaScript

[공부 필기] JavaScript 문법 공부 16일차 (3)

김간장 2022. 5. 7. 22:22

※ 필자는 초초초보자입니다.

※ 틀린 내용에 대한 피드백은 언제든지 환영합니다.

 

 

공부하고 있는 자료 : modern JavaScript tutorial 

https://ko.javascript.info/code-quality

 

코드 품질

 

ko.javascript.info

 

 


출처 : https://ko.javascript.info/testing-mocha

 

테스트 자동화와 Mocha

 

ko.javascript.info

 

✅ 테스트 자동화

- 코드를 수동으로 '재실행' 하면서 테스트를 하면 무언가를 놓치기 쉽다고 한다.

- 개발자는 무언가를 만들 때 머릿속에 수많은 유스 케이스(use case; '시스템을 사용하는 줄거리'라고 함)를 생각하며 코드를 작성하는데,

   코드를 변경해야할 때마다 모든 유스 케이스(use case)를 상기하면서 코드를 수정하는건 정말 힘든일이다.

 

- 이를 위해 사용하는 방법 중 하나가 '테스트 자동화'

- 테스트 자동화는 테스트 코드가 실제 동작에 관여하는 코드와 별개로 작성되었을 때 가능하다.

   또한 테스트 코드를 이용하면 함수를 다양한 조건에서 실행해 볼 수 있으며, 실행 결과와 기대 결과를 비교할 수도 있다.

 

✅ 개발 순서

- 개발에 착수하면 아래와 같은 순서로 개발이 진행된다고 한다.

  1. 명세서 초안을 작성한다. 초안에 기본적인 테스트도 들어간다.
  2. 명세서 초안을 보고 코드를 작성한다.
  3. 코드가 작동하는지 확인하기 위해 Mocha(테스트 프레임워크)를 사용해 명세서를 실행한다.
    이때, 코드가 잘못되었다면 에러가 출력된다.
    개발자는 테스트를 모두 통과해 에러가 더는 출력되지 않을 때까지 코드를 수정한다.
  4. 모든 테스트를 통과하면 코드 초안이 완성된다.
  5. 명세서에 지금까진 고려하지 않았던 유스케이스 몇 가지를 추가한다.
    테스트가 실패할 수도 있다.
  6. 3번 단계로 돌아가 테스트를 모두 통과할 때까지 코드를 수정한다.
  7. 기능이 완성될 때까지 3~6단계를 반복한다.

이렇게 하다 보면 종래에는 완전히 동작하는 코드와 테스트 둘 다를 확보하게 된다고 한다.

 

이제 이 과정을 BDD 방법론에 적용해보자.

 

✅ Behavior Driven Development 방법론

- 일명 BDD / 테스트, 문서, 예시를 한데 모아놓은 개념이라고 한다.

- 앞서 개발 순서의 가장 첫번째로 '명세서 초안을 작성한다'고 했다.

   코드를 작성하기 전에 먼저 해야할 일이 바로 '코드가 무슨 일을 하는지 상상하고 그걸 표현해놓는 것'이라고 한다.

   이때 만들어진 산출물이 바로 BDD에서는 "명세서"(또는 스펙)이다.

 

- BDD 방법론과 명세서는 실습을 하면서 배우라고 한다. (...)

- 실습을 위해 일단 거듭제곱 함수 구현 (거듭제곱 연산자 **를 사용하지 않고 거듭제곱하는 함수를 구현하기)

function pow(x, n) {
	let result = 1;
	for(let i = 0; i < n; i++) {
		result *= x;
	}
	return (result);
}

- BDD의 명세서 형태:

   아래와 같이 유스 케이스(use case)에 대한 자세한 설명과 테스트가 담겨있다고 한다.

   » 총 3가지로 구성된다.

   » describe("title", function() { ... })

      구현하고자 하는 기능에 대한 설명을 넣는다.

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

      첫번째 인수로 특정 유스 케이스에 대한 설명이 들어가며

      두번째 인수로 (유스 케이스) 테스트 함수가 들어간다.

  » assert.equal(value1, value2)

      assert.*는 pow가 예상한 대로 동작하는지 확인해주는 역할이다.

      즉, assert.equal(pow(2, 3), 8); 코드는 첫번째 인자 pow(2, 3)의 결과와 두번째 인자 8이 동등(equal)한지 확인하는 코드이며

      만약 다르면 에러를 반환한다.

describe("pow", function() { // pow 함수가 어떤 동작을 하는지에 대한 설명이 들어간다.

  it("주어진 숫자의 n 제곱", function() { // 특정 유스 케이스의 설명(주어진 숫자의 n제곱)과 테스트 함수가 들어간다.
    assert.equal(pow(2, 3), 8); // pow 함수를 제대로 구현했다면 it 블록 내의 코드 assert.equal(value1, value2)가 에러 없이 실행된다.
  });

});

// 출처 : 모던 자바스크립트 (https://ko.javascript.info/testing-mocha)

 

명세서 실행하기

- 명세서의 형태는 위에서 학습했다.

   이제 실행해야 하는데, 모던 자바스크립트에서는 총 3개의 라이브러리를 사용해 테스트를 진행하고 있다.

- Mocha, Chai, Sinon

   » Mocha : 핵심 테스트 프레임워크 (위의 명세서의 describe, it과 같은 테스트 함수/실행 관련 주의 함수를 제공한다)

   » Chai : 다양한 assertion을 제공해주는 라이브러리 (위의 코드에서는 assert.equal이 이에 해당함)

   » Sinon : 함수의 정보를 캐내는 데 사용되는 라이브러리, 내장 함수 등을 모방한다. (본 챕터에서는 사용 안한다고 한다)

 

- 위의 라이브러리들은 브라우저, 서버 사이드 환경을 가리지 않고 사용 가능하다고 한다.

 

- 사용방법은 모던 자바스크립트 글을 확인하면 된다.

https://ko.javascript.info/testing-mocha

 

테스트 자동화와 Mocha

 

ko.javascript.info

 

descirbe, it 등이 포함된 테스트 코드는 test.js에 적었고, 테스트 코드는 위에서 공부했던 코드를 그대로 썼다.

테스트 케이스를 잘 넘어가면 아래와 같은 화면이 출력된다.

 

✅ BDD와 Mocha에 대해서 좀 더 찾아보기

❖ TDD

- TDD, BDD 등은 모두 소프트웨어 개발 방법론 중 하나이다.

- BDD와 함께 흔히 등장하는 개념이 TDD이다.

- Test-Driven Development의 약자이며, 번역하면 "테스트 주도 개발" 정도라고 한다.

- 테스트(Test)를 먼저 작성하고, 그 테스트를 통과시키는 코드를 작성하는 흐름을 기본으로 하는 방법론이다.

- 자동화된 테스트 코드를 작성한 후 테스트를 통과하기 위한 코드를 개발하는 방식이라고 한다.

 

- TDD를 이용하는 방법은 간단하게 아래와 같다고 한다.

   1) 테스트 케이스를 작성한다.

   2) 테스트 케이스를 통과하는 코드를 작성한다.

   3) 반복한다.

   4) 작성한 코드를 리팩토링한다.

 

- TDD의 장점은 아래와 같다고 한다.

   1) 객체 지향적이니 코드 개발

   2) 설계 수정시간의 단축

   3) 유지보수(리팩토링)의 용이성

   4) 테스트 문서의 대체 가능

 

- 반대로 단점도 당연히 존재하며, 아래와 같다.

   1) 사전 준비 기간 필요

   2) 생산성 저하 우려

 

TDD Tool이나 장.단점에 대한 좀 더 많은 설명은 아래의 글을 읽어보면 될 것 같다.

출처 및 참고자료 : 

http://www.incodom.kr/%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%A3%BC%EB%8F%84_%EA%B0%9C%EB%B0%9C

 

 

❖ BDD

- Behavior-driven development, "행동 중심 개발" 정도로 해석할 수 있다.

- 이 또한 소프트웨어 개발 방법론 중 하나이다.

- 팀원들이 시스템의 예상된 행동을 논의해서 예상되는 기능에 관한 공통된 이해를 구축하는 방식이다.

 

- 이 방법은 '가능한 가장 작은 단위'가 아니라 '특정 기능을 제공'하는데 초점을 두는 것이라고 한다.

 

출처 : https://www.itworld.co.kr/news/109011

 

❖ Mocha

- JavaScript test framework이다.

- Mocha 외에도 자바스크립트 테스트 프레임워크는 여러가지가 있는 것 같다.

   » Jasmine, JEST, Karma 등

- 어쨌든 다양한 기능을 제공하는 툴인데,

   Mocha가 너무 궁금하다면 공식 사이트에서 정보를 확인하는 것도 좋을 듯 하다.

https://mochajs.org/

 

Mocha - the fun, simple, flexible JavaScript test framework

Mocha is a feature-rich JavaScript test framework running on Node.js and in the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct te

mochajs.org

 

chai 라이브러리에 대한 설명은 아래의 글을 읽어보면 좋을 것 같다.

https://velog.io/@goodlana/JavaScript-Chai-Mocha

 

JavaScript - Chai, Mocha

chai - assert 참조Chai는 테스트에 필요한 헬퍼 함수들이 담긴 라이브러리입니다.Chai는 이전에 만들었던 assert 함수와 동일한 기능을 하는 assert 함수를 제공합니다. 참조영어 문법에 가까운 코드로

velog.io

 

✅ Mocha 활용하기

- 시도1. it 블록을 생성해서 테스트 코드 추가하기

describe("pow", function() { 

	it("2의 3제곱은 8", function() { 
	  assert.equal(pow(2, 3), 8);
	  assert.equal(pow(3, 4), 81);
	});

	it("3의 4제곱은 81", function() {
		assert.equal(pow(3, 4), 81);
	});
  });
  
  // 출처 : 모던 자바스크립트 (https://ko.javascript.info/testing-mocha)

 

- 시도2. 수작업말고 반복문으로 테스트 코드 추가하기

describe("pow", function() { 
    
    function makeTester(n) {
        let expectedResult = n * n * n;
        it (`${n}의 3제곱 결과`, function() {
            assert.equal(pow(n, 3), expectedResult);
        });
    }

    for (let i = 1; i <= 5; i++) {
        makeTester(i);
    }

});

  
  // 출처 : 모던 자바스크립트 (https://ko.javascript.info/testing-mocha)

- 시도3. 중첩 describe으로 하위 그룹(subgroup) 정의하기

describe("pow", function() {
    
    describe("1~5까지 3 제곱", function() {

        function makeTester(n) {
            let expectedResult = n * n * n;
            it (`${n}의 3제곱 결과`, function() {
                assert.equal(pow(n, 3), expectedResult);
            });
        }

        for (let i = 1; i <= 5; i++) {
            makeTester(i);
        }

    });

    describe("1~5까지 4 제곱", function() {

        function makeTester(n) {
            let expectedResult = n * n * n * n;
            it (`${n}의 4제곱 결과`, function() {
                assert.equal(pow(n, 4), expectedResult);
            });
        }

        for (let i = 1; i <= 5; i++) {
            makeTester(i);
        }

    });
    
});

 

- 시도4. 음수, 정수가 아닌 값은 NaN으로 처리하도록 테스트 코드 추가하기

   » assert.isNaN 함수 사용하기

...

	describe("음수이거나 정수가 아니면 NaN", function() {

        it("음수이면 결과는 NaN", function() {
			assert.isNaN(pow(2, -1));
		});

		it("정수가 아니면 결과는 NaN", function() {
			assert.isNaN(2, 1.5);
		});

    });
 });

 

# isNaN, equal 등 더 많은 assertion은 공식 사이트에서 확인할 수 있다.

https://www.chaijs.com/api/assert/

 

Assert - Chai

The assert style is very similar to node.js’ included assert module, with a bit of extra sugar. Of the three style options, assert is the only one that is not chainable. Check out the Style Guide for a comparison. .include(haystack, needle, [message]) As

www.chaijs.com

 

 

 

[모던 자바스크립트 요약 일부 발췌]

BDD에선 스펙을 먼저 작성하고 난 후에 구현을 시작합니다. 구현이 종료된 시점에는 스펙과 코드 둘 다를 확보할 수 있습니다.
스펙의 용도는 세 가지입니다.
테스트 – 함수가 의도하는 동작을 제대로 수행하고 있는지 보장함
문서 – 함수가 어떤 동작을 수행하고 있는지 설명해줌. describe와 it에 설명이 들어감
예시 – 실제 동작하는 예시를 이용해 함수를 어떻게 사용할 수 있는지 알려줌

스펙이 있기 때문에 개발자는 안전하게 함수를 개선하거나 변경할 수 있습니다.
함수를 처음부터 다시 작성해야 하는 경우가 생겨도 스펙이 있으면 기존 코드와 동일하게 동작한다는 것을 보장할 수 있습니다.

코드가 바뀌어도 기존에 구현된 기능에 영향을 주지 않게 하는 건 대규모 프로젝트에서 매우 중요합니다.
프로젝트 규모가 커지면 함수 하나를 이곳저곳에서 사용하는데, 수동으로 변경된 함수가 이 함수를 사용하는 모든 곳에서 제대로 동작하는지 확인하는 건 불가능하기 때문입니다.

테스트를 하지 않고 코드를 작성해왔다면 개발자들은 둘 중 한 갈래의 길로 빠져버리고 맙니다.
아무 대책 없이 코드를 변경합니다.
부작용을 생각하지 않고 함수를 수정했기 때문에 어디선가 버그가 발생하고 맙니다.
수정이나 개선을 기피하게 됩니다.
버그의 대가가 가혹하기 때문이죠. 코드가 구식이 되어도 그 누구도 코드를 건드리려 하지 않습니다. 좋지 않은 상황이죠.

테스팅 자동화는 이런 문제를 피하게 도와줍니다!
테스팅 자동화를 수행하고 있는 프로젝트라면 이런 문제를 걱정하지 않아도 됩니다. 코드에 변화가 있어도 스펙을 실행해 테스트를 진행하면 몇 초 만에 에러 발생 여부를 확인할 수 있습니다.

 

실제로 최근에 어느 기능을 구현해야했다.

기본 흐름을 잡고 코드를 구현한 후, 테스터기를 만들어서 계속 돌리며 부족한 부분을 채워나갔는데..

그러다보니 부작용이 생기기도 했었다.

(기본 흐름을 잡고 코드를 작성했기 때문에 절대 수정하면 안되는 코드가 있었는데, 테스터기의 결과를 보완하겠다고 수정해버린 경우)

 

그래서 이번 글을 공부하면서, 테스트를 하면서 코드를 작성하는 방식을 채택해봐야겠다는 생각을 많이했다.

 

Comments