Wecode - Project 3 (부트캠프)/세션

Software Testing 2) - [TDD] 테스트 실습 + 추후에 따라해보기 **

JBS 12 2023. 10. 27. 16:14

A. 테스트 자동화 실습

Javascript를 테스트할 수 있는 도구로 Jest가 있습니다. 기존 모듈들을 Jest를 통해 테스트를 진행해보겠습니다.

 

1. 유닛(단위) 테스트 실습

 

아래에 계산기 프로그램 코드가 있습니다.

 

add 는 두 숫자를 받아서 더하는 함수, subtract 는 두 숫자를 받아서 빼는 함수, multiple 은 두 숫자를 받아서 곱하는 함수, divide 는 두 숫자를 받아서 나누는 함수 입니다.

 

 

 calculate.js 

unit 단위 테스트 코드 

현재 함수 단위로 나누어져 있음 
// calculate.js
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

function multiple(a, b) {
  return a * b;
}

function divide(a, b) {
  return a / b;
}

module.exports = { add, subtract, multiple, divide }

 

 

'단위 테스트' 작성 

calculate.test.js 파일
// calculate.test.js
const { add, subtract, multiple, divide } = require('./calculate');

describe('calculate unit test', () => {
  describe("add", () => {
    test("add(1,2)는 3이 되어야합니다.", () => {
      expect(add(1, 2)).toBe(3);
    });
  });

  describe("subtract", () => {
    test("subtract(2,1)는 1이 되어야합니다.", () => {
      expect(subtract(2, 1)).toBe(1);
    });
  });

  describe("multiple", () => {
    test("multiple(3, 4)는 12가 되어야합니다.", () => {
      expect(multiple(3, 4)).toBe(12);
    });
  });

  describe("divide", () => {
    test("divide(10, 2)는 5가 되어야합니다.", () => {
      expect(divide(10, 2)).toBe(5);
    });
  });
});

[분석을 위한 코드 재작성] 


const { add, subtract, multiple, divide } = require('./calculate');

describe('calculate unit test', () => {
  describe("add", () => {
    test("add(1,2)는 3이 되어야합니다.", () => {
      expect(add(1, 2)).toBe(3);
    });
  });

  describe("subtract", () => {
    test("subtract(2,1)는 1이 되어야합니다.", () => {
      expect(subtract(2, 1)).toBe(1);
    });
  });

  describe("multiple", () => {
    test("multiple(3, 4)는 12가 되어야합니다.", () => {
      expect(multiple(3, 4)).toBe(12);
    });
  });

  describe("divide", () => {
    test("divide(10, 2)는 5가 되어야합니다.", () => {
      expect(divide(10, 2)).toBe(5);
    });
  });
});

단위 테스트 코드 분석:

 describe 부분과 test 부분으로 나뉨

describetest 부분 둘 다
(description, callback) 형태를 가지며

- description 에는 해당 부분에 대한 카테고리 및 설명이 들어갑니다.
- callback 내부에는 다시 describe 및 test 를 선언할 수 있습니다.

 

test callback 내에서 기능 단위들(함수, 클래스 등)을 호출할 수 있으며

expect를 통해 값을 비교하여 정상적으로 수행했는지 확인 가능합니다.

 

 💡 하나의 테스트에 여러 개의 expect가 들어갈 수 있습니다!


 

테스트 코드를 실행 

여기서는 jest를 사용할 것이기 때문에 jest를 프로젝트 디렉토리 내에 설치합니다.

 

1) jest 설치 

2)  jest 명령어를 통해 테스트를 수행 

$ npm i -D jest
$ npx jest   # npx 명령어를 수행하면 프로젝트 내에 설치된 jest가 실행됩니다.

 

jest 프로그램이 *.test.js 나 *.spec.js 같은 테스트 코드 파일들을 찾아 자동으로 실행합니다.

 

 

아래는 실행 결과입니다.

- describe 이용:  해당 테스트가 무엇에 관한 테스트인지 캡션 달기가 가능

- describe 안에 describe가 들어가면 : 대분류 중분류 개념으로 내려간다 

 


2. 통합 테스트 실습

더하기 결과와 빼기 결과를 곱하는 과정을 통해

테스트를 통합

 

calculate.test.js

통합 테스트 코드 
// calculate.test.js
const { add, subtract, multiple, divide } = require('./calculate');

...기존 unit test

/// 통합 테스트 추가
describe("calculate integration test", () => {
  test("add(1, 3)과 subtract(4, 2)를 multiple한 결과는 8입니다.", () => {
    const addResult = add(1, 3);
    expect(addResult).toBe(4);
    const subtractResult = subtract(4, 2);
    expect(subtractResult).toBe(2);
    expect(multiple(addResult, subtractResult)).toBe(8);
  });
});

 

  • divide를 제외하고 add, subtract, multiple 함수들을 모아서 통합 테스트를 구성
  • 개별 단위 코드들을 모아서 테스트를 구성 ->  상향식 통합 테스트

(* 하향식 통합 테스트= 하향식으로 조립된 모듈 있을 때)

 


 

B. '테스트 커버리지 확인'하는 방법

[테스트 실행]

jest 에서는 --coverage라는 옵션 사용

npx jest --coverage

 

[실행 결과]

모든 구문과 분기점들을 100% 커버하는 점 확인

 

 

 


[여기서 add 함수에 코드를 추가]

function add(a, b) {
/// 추가된 부분
  if (b < 0) {
    throw new Error("b가 0보다 작습니다. subtract를 사용하세요!");
  }
/// ---------
  return a + b;
}

b 가 0보다 작을 때, 해당 함수의 기능을 종료하고 싶으면 실질적으로 subtract 를 사용

 

 

[테스트 실행]

이 후, 다시 jest 명령어 

npx jest --coverage

 

[실행 결과]

  • Funcs를 제외한 3가지의 커버리지가 낮아졌습니다.
  •  오른쪽 Uncovered Line 을 표시하여 어떤 라인이 커버 되지 않는지 알려주고 있습니다.

 

 

 


[그럼 이제, 테스트를 추가하여 커버리지를 다시 높여보도록]

describe("add", () => {
  test("add(1, 2)는 3이 되어야합니다.", () => {
    expect(add(1, 2)).toBe(3);
  });

  // 아래 테스트 추가
  test("add(1, -1)은 에러를 던집니다.", () => {
    try {
      add(1, -1);
    } catch (err) {
      expect(err).toBeInstanceOf(Error)
      expect(err).toHaveProperty("message", "b가 0보다 작습니다. subtract를 사용하세요!");
    }
  });
});

 

[테스트 실행]

npx jest --coverage

[실행 결과]

  • add 테스트를 추가하여 커버리지를 다시 높였습니다.
  • 추가한 테스트는 throw 부분을 실행하게 만들었으므로 해당 코드가 테스트되게 만들었습니다.
  • 커버리지는 테스트 입력을 추가하여 높일 수 있는 점 기억하시길 바라겠습니다.

 

 

💡 jest는 기본적으로 *.test.js, *.spec.js 파일들만 테스트하며 커버리지 산정은 테스트 파일내에서 import 된 코드만 이용해서 계산


E2E 테스트

 

 계산기 프로그램을 외부에 노출 시켜 누구나 사용가능하게 만들고 싶을 때, 우리는 서버 모듈을 사용합니다.

 

서버 모듈의 대표적인 프레임워크로 express가 있습니다.

 

 

계산기 함수를
 Express 프레임워크에 옮겨줍니다.
// app.js
const express = require("express"); // express 모듈은 npm i express로 설치
const { add, subtract, multiple } = require("./calculate");

const app = express();

// 쿼리 스트링으로 받는 a와 b를 숫자로 바꾸어서 다음 컨트롤러로 넘기는 미들웨어 입니다.
app.use((req, res, next) => {
  const { a, b } = req.query;

  req.num = {
    a: Number(a),
    b: Number(b),
  };

  next();
});

app.get("/add", (req, res) => {
  const { a, b } = req.num;

  const result = add(a, b);

  res.json({ result });
});

app.get("/subtract", (req, res) => {
  const { a, b } = req.num;

  const result = subtract(a, b);

  res.json({ result });
});

app.get("/multiple", (req, res) => {
  const { a, b } = req.num;

  const result = multiple(a, b);

  res.json({ result });
});

app.get("/divide", (req, res) => {
  const { a, b } = req.num;

  const result = divide(a, b);

  res.json({ result });
});

module.exports = app;

 

 

그런 다음 server.js 와 server.spec.js(혹은 server.test.js)를 만들어
아래의 코드를 붙여넣습니다.

 

설치하지 않은 모듈이 있으면 설치 후에 진행해주세요! (설치할 모듈은 아래 코드 주석에 있습니다!)

// server.js
const http = require("http"); // http 모듈은 node에 내장되어있으므로 설치 x
const app = require("./app");

http.createServer(app).listen(10010);

---
// server.spec.js
const http = require("http");
const fetch = require("node-fetch-commonjs"); // npm i node-fetch-commonjs
const app = require("./app");

describe("E2E Test", () => {
  let server;

  beforeEach(() => {
    // 테스트 케이스들이 독립된 환경에서 테스트할 수 있게 개별적으로 listen합니다.
    server = http.createServer(app).listen(10010);
  });

  afterEach(() => {
    // 각 테스트가 끝난후 서버를 종료시킵니다.
    server.close();
    // 가비지 컬렉터에서 http server 객체를 메모리에서 해제하게 만듭니다.
    server = null;
  });

  test("사용자가 a에 3, b에 4를 담아 add로 get 요청합니다.", async () => {
    const resBody = await fetch("<http://localhost:10010/add?a=3&b=4>").then(
      (res) => res.json()
    );

    expect(resBody.result).toBe(7);
  });

  test("사용자가 a에 6, b에 2를 담아 subtract로 get 요청합니다.", async () => {
    const resBody = await fetch("<http://localhost:10010/subtract?a=6&b=2>").then(
      (res) => res.json()
    );

    expect(resBody.result).toBe(4);
  });
});

 

[테스트 실행] 

npx jest를 실행하여 테스트 결과를 확인

 

 

[E2E 테스트란]

실제 환경과 동일하게 구성하여

사용자가 요청하는 것부터 시작하여 결과를 받는 것

모두 테스트하는 방법론이 

 

나머지 multiply와 divide는 개인별로 추가해보시면 되겠습니다.