Jest - Expect 기능 익히기 (3)

6 minute read

이번 포스트에서는 Jest 의 Expect 에 대해서 알아보겠습니다.



Expect 기능?

테스트를 작성할 때 값이 특정 조건을 충족하는지 확인할 필요가 있습니다. Expect는 여러가지 상황을 검증할 수 있는 수많은 Mathers 에 액세스 할 수 있게 도와줍니다.

추가 Jest Mathers 는 Jest-extended 에서 자세히 확인 가능합니다.

Methods

  • expect (value)
  • expect.extend (matchers)
  • expect.anything ()
  • expect.any (constructor)
  • expect.arrayContaining (array)
  • expect.hasAssertions ()
  • expect.assertions (number)
  • expect.not.arrayContaining (array)
  • expect.not.objectContaining (object)
  • expect.not.stringContaining (string)
  • expect.not.stringMatching (string or regexp)
  • expect.objectContaining (object)
  • expect.stringContaining (string)
  • expect.stringMatching (string or regexp)
  • expect.addSnapshotSerializer (serializer)
  • .not
  • .resolves
  • .rejects
  • .toBe (value)
  • .toHaveBeenCalled ()
  • .toHaveBeenCalledTimes (number)
  • .toHaveBeenCalledWith (arg1, arg2, …)
  • .toHaveBeenLastCalledWith (arg1, arg2)
  • .toHaveBeenNthCalledWith (nthCall, arg1, arg2)
  • .toHaveReturned ()
  • .toHaveReturnedTimes (number)
  • .toHaveReturnedWith (value)
  • .toHaveLastReturnedWith (value)
  • .toHaveNthReturnedWith (nthCall, value)
  • .toBeCloseTo (number, numDigits?)
  • .toBeDefined ()
  • .toBeFalsy ()
  • .toBeGreaterThan (number)
  • .toBeGreaterThanOrEqual (number)
  • .toBeLessThan (number)
  • .toBeLessThanOrEqual (number)
  • .toBeInstanceOf (Class)
  • .toBeNull ()
  • .toBeTruthy ()
  • .toBeUndefined ()
  • .toBeNaN ()
  • .toContain (item)
  • .toContainEqual (item)
  • .toEqual (value)
  • .toMatch (regexpOrString)
  • .toMatchObject (object)
  • .toMatchSnapshot (propertyMatchers?, hint?)
  • .toStrictEqual (value)
  • .toThrow (error?)


네! 이번에도 Expect 에 해당하는 매서드들은 많습니다. 하지만 두려워할 필요는 없습니다.
사용 가능한 메서드가 많아보이지만 각각의 명칭을 보면 어떤 동작을 하는 메서드인지 어느정도 예상할 수 있습니다.

물론 이번 포스트에서는 위에서 나열한 모든 메서드를 소개하진 않습니다. 많은 메서드중에 많이 사용되는 중요한 메서드만 소개하겠습니다. 설명하지 못한 메서드에대해서 자세히 알고 싶으시다면 Jest Api 소개 페이지에서 확인하시기 바랍니다.

.toBe (any)

.toBe를 사용하여 기본값을 비교하거나 Object 인스턴스의 참조 ID를 체크할 수 있습니다.
값을 비교하기 위해 Object.is 를 호출하므로 === (완전 항등 연산자) 보다 테스트할 때 더 좋습니다.

예를들어, 아래 코드는 can 객체의 일부 속성을 확인합니다.

const can = {
    name: 'pamplemousse', // 그레이프 프루트
    ounces: 12,
};
 
describe('the can', () => {
    test('12 온스', () => {
        expect(can.ounces).toBe(12); // can의 내용물의 질량이 12온스인지 테스트
    });
 
    test('세련된 이름이 있다', () => {
        expect(can.name).toBe('pamplemousse'); // can의 세련된 이름이 'pamplemousse' 인지 확인합니다
    });
});

[주의]
부동 소수점과 함께 .toBe를 사용하지 마세요. 예를들어, 반올림으로 인해 Javascript에선 0.2 + 0.1 은 엄격하게 0.3과 같지 않습니다. 부동 소수점을 사용해야 한다면 toBe 대신 toBeCloseTo 를 사용하세요.

.toBe 매처는 참조 ID를 확인하지만 어설션이 실패하면 값을 심도있게 비교합니다.
속성간의 차이로 테스트 실패의 원인을 파악할 수 없다면 (특히 결과값이 큰경우) expect 함수안으로 이동시켜 비교할 수 있습니다.
예를들어, 요소가 동일한 인스턴스인지 여부를 확인하려면 아래와 같이 테스트 할 수 있습니다.

  • expect(received).toBe(expected) 에서 expect(Object.is(received, expected)).toBe(true) 로 다시 작성하세요.
  • expect(received).not.toBe(expected) 에서 expect(Object.is(received, expected)).toBe(false) 로 다시 작성하세요.

.toEqual (value)

.toEqual은 객체 인스턴스의 모든 속성을 재귀적으로 비교할 수 있습니다.
원시값을 비교하기 위해 Object.is 를 호출하므로 완전 항등 연산자(===) 보다 테스트할 때 더 좋습니다.

const can1 = {
    flavor: 'grapefruit',
    ounces: 12,
};
const can2 = {
    flavor: 'grapefruit',
    ounces: 12,
};
 
describe('the La Croix cans on my desk', () => {
    test('have all the same properties', () => {
        expect(can1).toEqual(can2); // Object 구조가 동일하므로 테스트 통과
    });
    test('are not the exact same can', () => {
        expect(can1).not.toBe(can2); // 같은 Object 가 아니므로 테스트 통과
    });
});



.toBeNull ()

.toBeNull ()은 .toBe (null)과 동일하지만 오류 메시지가 조금 더 좋습니다. 따라서 무언가가 null인지 확인하려면 .toBeNull ()을 사용하십시오

function bloop() {
    return null;
}
 
test('bloop returns null', () => {
    expect(bloop()).toBeNull();
});



.toBeTruthy ()

.toBeTruthy () 는 .toBeFalsy 의 반대로, 값이 무엇인지와는 상관없이 boolean 컨텍스트에서 값이 true 인지 확인할때 사용할 수 있습니다.
JavaScript에는 false, 0, ‘’, null, undefined 및 NaN의 6 가지 falsy 값이 있습니다. 다른 모든 것은 truthy 입니다.

.toHaveLength (number)

.toHaveLength는 객체에 .length 속성이 있고 특정 숫자 값으로 설정되어 있는지 확인할 수 있습니다.

expect([1, 2, 3]).toHaveLength(3);
expect('abc').toHaveLength(3);
expect(' ').not.toHaveLength(5);



.toHaveProperty (keyPath, value?)

.toHaveProperty는 객체안에 참조 keyPath의 속성이 존재하는지 테스트할때 사용할 수 있습니다.
객체에서 깊이 중첩된 속성을 확인하려면 점 표기법 또는 keyPath가 포함된 배열을 사용할 수 있습니다.

수신된 특성 값을 비교하기 위해, 선택적으로 value 인수를 제공할 수 있습니다.

예를들어, 중첩 특성이 있는 houseForSale 이란 오브젝트를 가지고 아래와 같이 다양한 속성 존재 및 값 테스트를 할 수 있습니다.

// 테스트 할 주택 기능이 포함 된 객체
const houseForSale = {
  bath: true,
  bedrooms: 4,
  kitchen: {
    amenities: ['oven', 'stove', 'washer'],
    area: 20,
    wallColor: 'white',
    'nice.oven': true,
  },
  'ceiling.height': 2,
};
 
test('this house has my desired features', () => {
  // Example Referencing
  expect(houseForSale).toHaveProperty('bath');
  expect(houseForSale).toHaveProperty('bedrooms', 4);
  expect(houseForSale).not.toHaveProperty('pool');
 
  // 점 표기법을 사용한 깊은 참조
  expect(houseForSale).toHaveProperty('kitchen.area', 20);
  expect(houseForSale).toHaveProperty('kitchen.amenities', [
    'oven',
    'stove',
    'washer',
  ]);
 
  expect(houseForSale).not.toHaveProperty('kitchen.open');
 
  // keyPath를 포함하는 배열을 사용하는 깊은 참조
  expect(houseForSale).toHaveProperty(['kitchen', 'area'], 20);
  expect(houseForSale).toHaveProperty(
    ['kitchen', 'amenities'],
    ['oven', 'stove', 'washer'],
  );
  expect(houseForSale).toHaveProperty(['kitchen', 'amenities', 0], 'oven');
  expect(houseForSale).toHaveProperty(['kitchen', 'nice.oven']);
  expect(houseForSale).not.toHaveProperty(['kitchen', 'open']);
 
  // 키 자체에 점이있는 키 참조
  expect(houseForSale).toHaveProperty(['ceiling.height'], 'tall');
});



.toHaveBeenCalled ()

(또는 .toBeCalled())
.toHaveBeenCalled()는 모의 함수가 호출 되었는지 확인할 수 있습니다.

예를들어, drink라는 기능을 사용하여 가능한 모든 음료에 적용하는 drinkAll(drink, flavor) 기능이 있다고 가정해 봅시다.
당신은 ‘문어’ 가 아닌 ‘레몬’ 맛이 나는것을 체크하고 싶습니다. 왜냐면 ‘문어’ 맛은 정말 이상하니까요. 그렇다면 아래처럼 테스트를 진행할 수 있습니다.

// 검증대상 함수
function drinkAll(callback, flavor) {
    if (flavour !== 'octopus') {
        callback(flavor);
    }
}
 
describe('drinkAll', () => {
    test ('레몬맛이 나는 음료', () => {
        const drink = jest.fn(); // 모의 callback 함수를 생성한다.
        drinkAll(drink, 'lemon');
        expect(drink).toHaveBeenCalled(); // drink 함수에 'lemon' 을 적용했을때 callback 함수가 발동하는지 체크
    });
    test ('문어맛이 나는 음료는 마시지 않는다', () => {
        const drink = jest.fn();
        drinkAll(drink, 'octopus');
        expect(drink).not.toHaveBeenCalled(); // .not 을 사용해서 부정값이 참임을 확인합니다.
    });
});



expect.objectContaining (object)

expect.objectContaining (object) 는 예상되는 속성과 재귀적으로 일치하는 수신된 객체와 일치합니다.
expected 객체는 수신된 객체의 하위 집합입니다. 따라서 expected 객체에 있는 속성이 포함된 수신된 객체와 일치합니다.

즉, 검증할 객체가 있고 테스트를 위한 예상 객체가 있을경우, 검증대상 객체안에 예상되는 객체의 요소들이 포함되어 있는지를 확인하고 일치하면 테스트를 통과한다.

예를들어, 검증하고 싶은 콜백의 리턴 객체에 event.x 및 event.y 속성이 있는지 확인하고 싶다면 아래처럼 할 수 있습니다.

// 검증할 simulatePresses 함수
const simulatePresses = (callback) => {
    callback({ x: 3, y:5 });
};
 
 
test ('onPress가 옳은 일을하고 있습니다.', () => {
    const onPress = jest.fn();
    simulatePresses(onPress);
    expect(onPress).toBeCallWith(
        expect.objectContaining({ // onPress 가 동작할때 수신되는 객체값에 아래의 x, y 의 값이 포함되는지 테스트
            x: expect.any(Number), // Number 타입인지 검증
            y: expect.any(Number), // Number 타입인지 검증
        });
    );
});



expect.arrayContaining (array)

expect.arrayContaining(array)는 수신된 배열에 예상되는 배열의 요소들이 포함되는지 판단합니다.

즉, 예상되는 배열은 수신된 배열의 하위 집합입니다.

리터럴 값 대신 사용할 수 있습니다.

  • toEqual 또는 toBeCalledWith 안에서 사용할 수 있습니다.
  • objectContaining 또는 toMatchObject 의 속성과 일치합니다.
describe('arrayContaining', () => {
    const expected = ['Alice', 'Bob'];
    it ('수신된 요소가 예상 요소를 포함하고 있으면 일치합니다.', () => {
        expect(['Alice', 'Bob', 'Eve']).toEqual(expect.arrayContaining(expected));
    });
    it ('수신된 요소가 예상 요소를 포함하지 않으면 일치하지 않습니다.', () => {
        expect(['Bob', 'Eve']).not.toEqual(expect.arrayContaining(expected));
    });
});
describe('Beware of a misunderstanding! A sequence of dice rolls', () => {
    const expected = [1, 2, 3, 4, 5, 6];
    it ('예기치 않은 숫자 7이 있지만 일치합니다.', () => {
        expect([4, 1, 6, 7, 3, 5, 2, 5, 4, 6]).toEqual( expect.arrayContaining(expected) ); // 수신요소에는 예상요소의 7이 없지만 하위 요소를 모두 포함하므로 일치한다.
    });
    it ('예상되는 번호 2가 없으면 일치하지 않습니다.', () => {
        expect([4, 1, 6, 7, 3, 5, 7, 5, 4, 6]).not.toEqual( expect.arrayContaining(expected) ); // 예상요소에 수신요소의 2가 포함되어있지 않아 일치하지 않는다.
    });
});



expect.stringMatching (string | regexp)

expect.stringMatching(string | regexp)은 예상 문자열 또는 정규식과 일치하는 문자열인 경우 수신된 값과 일치합니다.

즉, 검증 대상 문자열에 테스트할 예상 문자가 정확히 일치하거나 정규식 규칙이 정확히 맞을 경우 테스트를 통과합니다.

리터럴값 대신 사용할 수 있습니다.

  • toEqual 또는 toBeCalledWith 에서 사용 가능합니다.
  • arrayContaining의 요소와 일치
  • objectContaining 또는 toMatchObject 의 속성과 일치

예를들어, expect.arrayContaining 안에 expect.stringMatching 을 사용하여 여러 비대칭 매처를 중첩으로 사용할 수 있습니다.

describe('arrayContining 안에서 stringMatching', () => {
  const expected = [
    expect.stringMatching(/^Alic/), // 특정 요소의 값이 regexp 에 정의된 규칙에 일치하는지 판단. 예로 Alic.. 라는 단어로 테스트하면 일치
    expect.stringMatching(/^[BR]ob/), // 특정 요소의 값이 regexp 에 정의된 규칙에 일치하는지 판단. 예로 Bob.. 또는 Rob... 라는 단어로 테스트하면 일치
  ];
  it ('추가 요소가 포함된 경우에도 일치합니다.', () => {
    expect(['Alice', 'Roberto', 'Evelina']).toEqual(
      expect.arrayContaining(expected), // arrayContaining 으로 ['Alice', 'Roberto', 'Evelina'] 에 /^Alic/ 또는 /^[BR]ob/ 의 문자열을 포함하는지를 테스트
    );
  });
  it ('수신된 요소가 예상 요소를 포함하지 않으면 일치하지 않습니다.', () => {
    expect(['Roberto', 'Evelina']).not.toEqual(
      expect.arrayContaining(expected), // 검증 array 요소안에는 expected의 요소(/^Alic/)가 일치하지 않습니다.  not.toEqual 이므로 테스트는 일치
    );
  });
});




모든 기능을 한 페이지에서 설명한다는것은 참 어렵습니다.
시간이 되신다면 또는 업무시에 Jest 를 이용해 테스트 케이스를 작성하고 작동시켜야 한다면 Jest 홈페이지에서 필요한 기능을 검색하고 사용하시는것을 추천드립니다.

추가 Jest Mathers 는 Jest-extended 에서 자세히 확인 가능합니다.

Tags:

Categories:

Updated:

 

 

Leave a comment