Jest 맛보기

백동우·2023년 1월 25일
0
post-thumbnail

기본 구조

설치

  • npm i jest --save-dev

package.json수정

// package.json
  "scripts": {
    "test": "jest",
    ...prev

_ test _ dir 안에 있거나 name.test.js 와 같은 형식에 파일은 테스트파일로 인식한다

구조

fn=> 간단 파라미터 두개 값 더하는 함수 import

test("설명 칸입니다", () => {
  //설명
  expect(1).toBe(1);
  // expect 검증할 대상
  // toBe에 기대되는 값 (반환 값)
});

test("3 + 3 =6", () => {
  expect(fn.add(3, 3)).toBe(6);
});

test("3 + 3 !==7", () => {
  expect(fn.add(3, 3)).not.toBe(7);
});

실행 결과(오류 부분)

-> 설명칸을 통해서 오류 파악이 가능

Machers Macher 공식문서

-> tobe 부분에서 사용하는 함수를 "Macher" 라고 합니다

ex)

  1. toEquals : 객체나 배열은 재귀적으로 돌기때문에 toBe가 아닌 toEquals사용

  2. toBeTruthy() / toBeFalsy() : true면 테스트 통과 /false면 테스트 통과

  3. toBeCalled() : 함수가 호출되었으면 통과

  4. toHaveLength() : 배열의 길이를 체크하여 테스트 통과 여부

  5. toContain() : 특정 원소가 배열에 들어있으면 통과

  6. toBeNull : Null이면 통과

  7. toBeGreaterThan : 초과

  8. toBeGreaterThanEqual : 이상

  9. toBeLessThan : 미만

  10. toBeLessThanEqual : 이하

  11. toThrow: 예외 발생 여부를 테스트
    ... 공식문서 참고

비동기 코드

try catch 사용

 getName: (callback) => {
    const name = "velog";
    setTimeout(() => {
      callback(name);
    }, 3000);
  },
...
//
test("3초후 받아온 이름은 velog", (done) => {
  const callback = (name) => {
    try {
      expect(name).toBe("velog");
      done();
    } catch (e) {
      done();
    }
  };
  fn.getName(callback);
});

// done을사용하지 않을시 테스트에 오류가 나오지 않는다
// done이 호출되면 종료됩니다
// done사용 안할시 0.1ms가 걸림

Promise사용

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

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

test("3초후 받아온 나이는 30최소화", () => {
  return expect(fn.getAge()).resolves.toBe(30);
});
 //.rejects로는 에러를 반환

async await

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

test("3초후 받아온 나이는 30최소화", async () => {
  await expect(fn.getAge()).resolves.toBe(30);
});

테스트 전후 작업

에러 발행 코드

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);
});
  • 초기화가 되지않고 에러가 발생

해결 (beforeEach)

  • 상단에 추가
beforeEach(() => {
  //  각 테스트 직전 실행
  num = 0;
});
  • beforeEach: 테스트 직전 실행

  • afterEach: 테스트 직후 실행

  • beforeAll : 전체 테스트 직전 실행 (1번)

  • afterEachAll : 전체 테스트 직후 실행 (1번)

//비슷한 기능 묶음
describe("Car 관련 진업", () => {
  let car;
  beforeAll(async () => {
    car = await fn.connectCarDb();
  });
  afterAll(async () => {
    car = await fn.connectCarDb();
  });
  test("브랜드 BMW", () => {
    expect(car.brand).toBe("BMW");
  });
});

-> describe로 묶으면 해당 부분처럼 구분 지어서 확인가능

Error debuging

  • 다음과 같이 한개만 오류가 나왔을 경우 전체 실행은 비효율적이므로 한가지만 실행 보면 좋습니다
// only를 추가하여 한가지만 테스트를 진행ㄹ

test.only("0 + 3 =3", () => {
  expect(fn.add(num, 3)).toBe(4);
});


// skip시 해당 테스트만 제외하고 진행이 가능
test.skip("0 + 3 =3", () => {
  expect(fn.add(num, 3)).toBe(4);
});

Mock Function(목 함수)

  • 테스트 하기위해 모형 함수

mock.calls

const mockFn = jest.fn();

mockFn();
mockFn(1);

test("mock 테스트", () => {
  console.log(mockFn.mock.calls);
  expect("test").toBe("test");
});

결과

console.log [ [], [ 1 ] ]
  • 함수 호출 횟수, 파라미터 파악이 가능합니다.

mock.results

const mockFn = jest.fn((num) => num + 1);

mockFn(10);
mockFn(20);
mockFn(30);

test("함수 호출은 3번", () => {
  console.log(mockFn.mock.results);
  expect(mockFn.mock.calls.length).toBe(3);
});

결과

const mockFn = jest.fn();
mockFn
  .mockReturnValueOnce(true)
  .mockReturnValueOnce(false)
  .mockReturnValueOnce(true)
  .mockReturnValueOnce(false)
  .mockReturnValue(true);
const results = [1, 2, 3, 4, 5].filter((num) => mockFn(num));
test("홀수 는 1,3,5", () => {
  expect(results).toStrictEqual([1, 3, 5]);
});

mockReturnValueOnce , mockReturnValue

  • 실행시 각각 다른 값을 return
  createUser: (name) => {
    console.log("실제로 사용자가 생성");
    return {
      name,
    };
  },


  test("유저 생성", () => {
  const user = fn.createUser("Mike");
  expect(user.name).toBe("Mike");
});
  • 콘솔이 찍히는것을 확인 가능
jest.mock("./fn");
fn.createUser.mockReturnValue({ name: "Mike" });
  • 2줄 추가시 mock함수가 실행이 되어 테스트는 통과 되지만 콘솔은 찍히지 않음

React Component + 스냅샷 테스트

  • npx create-react-app "name"
  • CRA 에서 test는 jest를 사용(별도 설치 필요없습니다)
Hello.js
const Hello = ({ user }) => {
  return user?.name ? (
    <div>
      <h1>Hello! {user.name}</h1>
    </div>
  ) : (
    <button>로그인</button>
  );
};
--------
Hello.test.js
test("Hello라는 글자가 포함되는가", () => {
  render(<Hello user={user} />);
  const helloEl = screen.getByText(/Hello/i);
  expect(helloEl).toBeInTheDocument();
});

-> 문자에 Hello가 포함 여부 테스트

스냅샷

  • 성공하는 테스트 케이스를 찍어두고 비교하는 방식
const user = {
  name: "Mike",
  age: 30,
};

const user2 = {
  age: 30,
};
test("snapshot : name 있음", () => {
  const el = render(<Hello user={user} />);
  expect(el).toMatchSnapshot();
});

test("snapshot : name 없음", () => {
  const el = render(<Hello user={user2} />);
  expect(el).toMatchSnapshot();
});

결과화면

-> 해당 부분이 변경이 되면 오류생김(이름 or 모든 부분)

스냅샷 업데이트

-> u 를 클릭시 스냅샷 업데이트 (버그 잘 찾고 하셔야합니다)

Mock함수를 사용 리액트

  • 해당 컴포넌트를 실행 후 테스트 스냅샷을 작성
    현재 {new Date(Date.now()).getSeconds()}초 입니다
    -> 초가 변경되므로 테스트 진행 마다 값이 틀려서 테스트케이스를 통과 하지못합니다
test("초 표시", () => {
  Date.now = jest.fn(() => 123456789);
  const el = render(<Timer />);
  expect(el).toMatchSnapshot();
});

-> 테스트는 항상 고정된 값으로 사용되므로 mock함수를 통해서 처리가 가능합니다~

수정이 자주 일어나는 화면 같은경우는 스냅샷 기능을 자제해야합니다

강의링크

0개의 댓글