Computer기본지식/리팩터링

리팩터링 Chapter 4 - 테스트 구축하기

HOONY_612 2021. 9. 2. 19:04
반응형

 

 

이번 4장은 테스트를 어떻게 작성하고 작성한 것을 바탕으로 리팩터링하는 방법을 가르쳐줍니다.

저도 Spring을 공부하면서 무작정 기능을 개발하는 습관이 있었습니다.

예외적인 부분과 경계부분은 전혀 고려하지 않았습니다.

이 챕터를 읽고나서는 코드를 짜는 방식에 대한 생각이 완전히 바뀌었습니다.

기능을 구현하기 전 무조건 기능에 대한 테스트 코드를 작성하고 그것에 맞춰가는 방식으로 코드를 구성할 예정입니다.

이것이 바로 TDD(Test Driven Development)입니다. 4장을 정리해보겠습니다.

 

4-1 자가 테스트 코드의 가치

실제 프로그래머들이 코드를 작성하는 시간의 비중은 크지 않습니다.

대부분의 시간을 설계 및 버그 수정에 시간을 쏟아 붓습니다.

작업을 효율적으로 해줄 수 있는 방법이 테스트를 작성하는 것입니다.

 

모든 테스트를 완전히 자동화하고 그 결과까지 스스로 검사하게 만들자.

위의 말처럼하면 컴파일만큼 테스트를 실행하는 것이 쉬워져 자주 수행할 수 있습니다.

이것은 곧 생산성 향상에 큰 도움을 줍니다. 이러한 프로그램 테스트의 대표적인 것이 Junit입니다.

테스트를 작성하기 가장 좋은 시점은 프로그래밍 시작 전입니다.

테스트 구성 후 기능 개발을 하면 구현보다 인터페이스에 집중 할 수 있고 원하는 기능을 명확하게 알 수 있습니다.

이러한 개발 기법이 TDD(Test Driven Development)입니다.

테스트 - 코딩 - 리팩터링 과정을 깔끔히 진행 할 수 있습니다.

 

4-2 테스트할 샘플 코드

Github참고 바랍니다.

 

4-3 첫 번째 테스트

테스트 프레임워크는 모카를 사용하겠습니다. 아래는 모카의 기본구조입니다.

describe('province', function() {
  if('shortfall', function() {
    const asia = new Province(sampleProvinceData());
    assert.equal(asia.shortfall,5);
  });
});

 

자주 테스트하라. 작성 중인 코드는 최소한 몇 분 간격으로 테스트하고, 적어도 하루에 한 번은 전체 테스트를 돌려보자.

만약 테스트 중 빨간 막대(실패)가 보이면 리팩터링을 하지말고 마지막으로 테스트를 통과했던 부분

으로 돌아가서 초록 막대(성공)로 되돌려야합니다.

 

4-4 테스트 추가하기

테스트는 위험요소를 중심으로 작성해야합니다. 단순한 필드 읽기, 쓰기는 할 필요가 없습니다.

완벽한 테스트를 만드느라 수행 못하느니 불완전한 테스트라도 작성해 실행하는 게 낫습니다.

그리고 테스트 여러 개 수행 시 공유 픽스처를 사용하면 안됩니다.

공유 픽스처를 사용 할 경우 BeforeEach문을 사용하여 초기화를 시켜줘야합니다.

 

* Mocha의 기본적인 사용법

테스트 코드 작성을 위한 툴로 Mocha 프레임워크에대해 알아보겠습니다.

NodeJS 테스트 코드를 작성할 경우 대부분 사용된다고 합니다.

처음으로 NPM을 이용하여 다운받습니다. 의존성도 추가해줍니다.

테스트를 실행하고 테스트 결과를 터미널에 로깅하는 기능을 제공합니다.

Chai는 Mocha에서 일반적으로 사용되는 어서션 라이브러리입니다.

$ npm install --global mocha
$ npm install --save-dev mocha
$ npm install --save-dev chai

assertion, expect, hookers의 기능만 사용할 것입니다.

비동기 부분을 잡아내는 것과 다양한 기능들은 다음에 설명하겠습니다.

파일을 아래와 같이 생성합니다. app.js는 모듈화 하고 싶은 함수를 만들어줍니다.

app.spec.js, province.spec.js는 그 모듈을 가져와 실행하여 테스트하는 함수를 만들어줍니다.

저는 app을 쓰지 않지만 app.js를 생성안해주면 mocha에서 app.js없다고 에러를 띄웁니다.

<province.spec.js>

const { assert, expect } = require("chai");

describe("province", function () {
    let asia;
    beforeEach(function () {
        asia = new Province(sampleProvinceData());
    });
    // 생산 부족분을 제대로 계산하는지
    it("shortfall", function () {
        assert.equal(asia.shortfall, 5);
    });
});

일단 테스트는 describeit으로 구성되어 있습니다.

describe테스트 스위트를 만들어줍니다. it개별 테스트를 넣어줍니다.

describeit의 구분은 개발자마다 기준이 다르기 때문에 각자 생성하시면 됩니다.

아래의 예시는 기본 예시입니다. beforeEach라는 Hooker를 이용하여 it 공통변수를 초기화해줍니다.

before같은 경우는 describe기준으로 실행되어집니다.

 

4-5 픽스처 수정하기

보통 세터같은 경우는 잘 테스트하지 않습니다. 그러나 복잡한 세터 같은 경우에는 테스트를 수행해

봐야합니다. 아래와 같은 경우입니다. 주의 점은 테스트가 두 개가 있으면 앞 부분이 실패할 경우

뒷 부분은 수행되지 않는다는 점입니다. 상황에 맞게 잘 분리하면 될 것 같습니다.

const { assert, expect } = require("chai");

describe("province", function () {
    let asia;
    beforeEach(function () {
        asia = new Province(sampleProvinceData());
    });
    // 생산 부족분을 제대로 계산하는지
    it("shortfall", function () {
        assert.equal(asia.shortfall, 5);
    });
});

 

4-6 경계 조건 검사하기

앞의 코드는 기본 상황에 집중 하였다면 이제는 경계 지점에서 생기는 문제를 확인해봐야합니다.

예를 들어 Produce에 생성자가 없는 경우 생산 부족분을 제대로 계산 하는지 수요에 음수가 들어갈

경우 어떻게 처리해야하는지에 대한 테스트가 이루어져야합니다.

const { assert, expect } = require("chai");

describe("province", function () {
    let asia;
    beforeEach(function () {
        asia = new Province(sampleProvinceData());
    });
    // 생산 부족분을 제대로 계산하는지
    it("shortfall", function () {
        assert.equal(asia.shortfall, 5);
    });
});

 

4-7 끝나지 않은 여정

단위 테스트란 코드의 작은 영역만을 대상으로 빠르게 실행되도록 설계된 테스트입니다.

이러한 단위 테스트는 자가 테스트 코드의 핵심입니다.

중요한 습관은 즉시 발견한 버그를 명확히 잡아내는 테스트를 작성하는 습관을 들이는 것입니다.

 

 

이렇게 4장에 대해서 알아봤습니다. 백엔드 개발을 공부 중인 저에게 엄청난 도움이 되었던 챕터였습니다.

처음엔 TDD라는 개념이 그냥 테스트를 짜서 돌리고 되면 그만이구나라고 생각했습니다.

그러나 테스트를 위주로 구현을 맞춰가는 방식이라는 것은 처음 알게되었습니다.

지금까지 4장 정도를 읽은 부분 중에서 가장 가슴에 와닿는 챕터였습니다.

반응형