관리 메뉴

SW

Jest 본문

대학교/FE

Jest

SWKo 2021. 1. 31. 01:41

0. Jest란?

- 페이스북에서 만든 테스트 프레임워크


1. 사용 방법

1-1. 설치

npm install jest --save-dev

1-2. package.json의 scripts를 다음과 같이 수정

package.json

1-3. 코드 작성

 

* fn.js

const fn = {
    add: (num1, num2) => (num1 + num2),
};

module.exports = fn;

* fn.test.js

const fn = require('./fn');

test('1은 1이야.', () => {
    expect(1).toBe(1);
});

test('2더하기 3은 5야.', () => {
    expect(fn.add(2, 3)).toBe(5);
});

test('3더하기 3은 5야.', () => {
    expect(fn.add(3, 3)).toBe(5);
});

test('3더하기 3은 5가 아니야.', () => {
    expect(fn.add(3, 3)).not.toBe(5);
});

1-4. 실행

npm test

1-5. 결과값

 


2. Matcher

  • toBe부분에서 사용하는 함수를 Matcher라고 한다.
  • toBe는 숫자나 문자 등 기본 타입값을 비교할 때 사용하며 toBe 이외에도 toEqual 등 여러 Matcher가 존재한다.
  • 자주 사용되는 Matcher
    더보기
    toBe, toEqual, toStrictEqual, toBeNull, toBeUndefined, toBeDefined, toBeTruthy, toBeFalsy, toBeGreaterThan, toBeGreaterThanOrEqual, toBeLessThan, toBeLessThanOrEqual, toBeCloseTo, toMatch, toThrow
  • https://jestjs.io/docs/en/using-matchers
 

Jest · 🃏 Delightful JavaScript Testing

🃏 Delightful JavaScript Testing

jestjs.io


3. 비동기 코드 테스트

3-1. 코드 작성

const fn = {
    getName: callback => {
        const name = "Mike";
        setTimeout(() => {
            callback(name);
        }, 3000);
    },
};

module.exports = fn;

3-2. 테스트 코드

- 다음과 같이 코드를 작성하면 toBe에 Mike가 아닌 다른 값이 와도 테스트를 성공함

- Jest는 실행이 끝이 도달하게 되면 기다리지 않고 그대로 끝나게 된다. 

const fn = require('./fn');

test('3초 후에 받아온 이름은 Mike', () => {
    const callback = name => {
        expect(name).toBe('Mike');
    }
    fn.getName(callback);
})

- 그러한 문제를 방지하기 위해 done이라고 하는 콜백함수를 전달해주면 된다.

- done이 호출될 때까지 jest는 테스트를 끝내지 않고 기다리게 된다.

const fn = require('./fn');

test('3초 후에 받아온 이름은 Mike', (done) => {
    const callback = name => {
        expect(name).toBe('Mike');
        done();
    }
    fn.getName(callback);
})

3-3. api 에러와 같은 경우 에러를 감지하고 싶다면 try/catch 사용

- 코드

const fn = {
    getName: callback => {
        const name = "Mike";
        setTimeout(() => {
            // callback(name);
            throw new Error("서버 에러..");
        }, 3000);
    },
};

module.exports = fn;

- 테스트 코드

const fn = require("./fn");

test("3초 후에 받아온 이름은 Mike", (done) => {
  const callback = (name) => {
    try {
      expect(name).toBe("Mike");
      done();
    } catch (error) {
      done();
    }
  };
  fn.getName(callback);
});

- 결과

3-4. Promise 테스트 코드 : return을 붙여줘야 함

- 코드 

const fn = {
  getAge: () => {
    const age = 30;
    return new Promise((res, rej) => {
      setTimeout(() => {
        res(age);
      }, 3000);
    });
  },
};

module.exports = fn;

- 테스트 코드

const fn = require("./fn");

test("3초 후에 받아온 나이는 30", () => {
  return fn.getAge().then((age) => {
    expect(age).toBe(30);
  });
});

// resolves라는 Matcher를 사용한 경우
test("3초 후에 받아온 나이는 30", () => {
  return expect(fn.getAge()).resolves.toBe(30);
});

// async/await 사용한 경우
test("3초 후에 받아온 나이는 30", async () => {
  const age = await fn.getAge();
  expect(age).toBe(30);
});

// resolves라는 Matcher와 async/await 사용한 경우
test("3초 후에 받아온 나이는 30", async () => {
  await expect(fn.getAge()).resolves.toBe(30);
});

- 결과


4. 테스트 전후 작업

4-1. 코드 작성

- 코드

const fn = {
  add: (num1, num2) => num1 + num2,
};

module.exports = fn;

- 테스트 코드

const fn = require("./fn");

let num = 0;

test("0 더하기 1은 1이야.", () => {
  num = fn.add(num, 1);
  expect(num).toBe(1);
});

test("0 더하기 2는 2이야.", () => {
  num = fn.add(num, 2);
  expect(num).toBe(2);
});

test("0 더하기 3은 3이야.", () => {
  num = fn.add(num, 3);
  expect(num).toBe(3);
});

test("0 더하기 4은 4이야.", () => {
  num = fn.add(num, 4);
  expect(num).toBe(4);
});

- 결과

4-2. 무엇이 잘못되었나?

- num이 0으로 초기화되지 않고 누적되어 더해짐 => 각 함수 직전에 실행되는 beforeEach라는 Helper 함수를 사용

 

4-3. beforeEach, afterEach

- beforeEach 테스트 코드

const fn = require("./fn");

let num = 0;

beforeEach(() => {
    num = 0;
});

test("0 더하기 1은 1이야.", () => {
  num = fn.add(num, 1);
  expect(num).toBe(1);
});

test("0 더하기 2는 2이야.", () => {
  num = fn.add(num, 2);
  expect(num).toBe(2);
});

test("0 더하기 3은 3이야.", () => {
  num = fn.add(num, 3);
  expect(num).toBe(3);
});

test("0 더하기 4은 4이야.", () => {
  num = fn.add(num, 4);
  expect(num).toBe(4);
});

- beforeEach 결과

- afterEach 코드(초기값을 10으로 설정)

const fn = require("./fn");

let num = 0;

afterEach(() => {
    num = 0;
});

test("0 더하기 1은 1이야.", () => {
  num = fn.add(num, 1);
  expect(num).toBe(1);
});

test("0 더하기 2는 2이야.", () => {
  num = fn.add(num, 2);
  expect(num).toBe(2);
});

test("0 더하기 3은 3이야.", () => {
  num = fn.add(num, 3);
  expect(num).toBe(3);
});

test("0 더하기 4은 4이야.", () => {
  num = fn.add(num, 4);
  expect(num).toBe(4);
});

- afterEach 결과

4-4. 만약 전후작업이 시간이 오래걸리는 작업이라면?

- DB를 연결하고 끊는 작업을 매번 테스트마다 한다고 가정해보자.

- 코드

const fn = {
  connectUserDb: () => {
    return new Promise((res) => {
      setTimeout(() => {
        res({
          name: "Mike",
          age: 30,
          gender: "male",
        });
      }, 500);
    });
  },
  disconnectDb: () => {
    return new Promise((res) => {
      setTimeout(() => {
        res();
      }, 500);
    });
  },
};

module.exports = fn;

- 테스트 코드

const fn = require("./fn");

let user;

beforeEach(async () => {
  user = await fn.connectUserDb();
});

afterEach(() => {
  return fn.disconnectDb();
});

test("이름은 Mike", () => {
  expect(user.name).toBe("Mike");
});

test("나이는 30", () => {
  expect(user.age).toBe(30);
});

test("성별은 남성", () => {
  expect(user.gender).toBe("male");
});

- 결과 : 각 작업마다 시간이 1초 이상 소요된다. 그런데 이 예시처럼 DB를 연결하고 끊는 작업을 매번 해줘야할까? 아니다. 최초에 한번, 최후에 한번만 실행해주면 된다. 이때, 사용할 수 있는 것이 beforeAll, afterAll 이다.

- beforeAll, afterAll 사용한 테스트 코드

const fn = require("./fn");

let user;

beforeAll(async () => {
  user = await fn.connectUserDb();
});

afterAll(() => {
  return fn.disconnectDb();
});

test("이름은 Mike", () => {
  expect(user.name).toBe("Mike");
});

test("나이는 30", () => {
  expect(user.age).toBe(30);
});

test("성별은 남성", () => {
  expect(user.gender).toBe("male");
});

- beforeAll, afterAll 사용 결과 : 시간이 단축되었다.

 

'대학교 > FE' 카테고리의 다른 글

[Apollo-Client] useQuery사용 시 update 방법  (0) 2020.08.12
[React & RN] Styled Components  (0) 2020.04.14
[React Hooks] Hooks (2)  (0) 2020.04.07
[React-Native] react-native init  (0) 2020.04.02
[Redux] Pure Redux: To Do List  (0) 2020.04.01
Comments