-
[Jest] object에 대한 다양한 matcher 함수들Javascript, Typescript 2021. 12. 31. 14:07반응형
facebook에서 개발 및 유지보수 중인 자바스크립트의 대표적인 테스팅 라이브러리인 Jest는 다양한 matcher함수를 제공한다.
그중 두 오브젝트를 비교할 때 사용할 수 있는 다양한 matcher 함수 중 비슷하면서도 다른
toBe
,toEqual
,toStrictEqual
,toMatchObject
함수의 동작과 그에 따른 차이점을 알아보자.toBe()
기본형을 비교할 때 가장 많이 사용되는 toBe 함수는 두 값이 같은지 비교한다.
비교 대상이 기본형(primitive type)이라면 두 원시 값이 같은지 비교하고, 오브젝트(object type)라면 같은 오브젝트에 대한 참조인지를 비교(Shallow compare)한다.
두 값에 대해서
===
과는 다르게 동작하는Object.is
를 수행한다.(두 연산의 차이)- number에 대한 비교
describe('toBe', () => { test('success', () => { const original = 1; expect(original).toBe(1); // <- success }); test('fail', () => { const original = 1; expect(original).toBe(3); // <- fail }); });
- string에 대한 비교
describe('toBe', () => { test('success', () => { const original = 'original'; expect(original).toBe('original'); // <- success }); test('fail', () => { const original = 'original'; expect(original).toBe('different'); // <- fail }); });
- object에 대한 비교
오브젝트에 대해서 얕은 비교를 하기 때문에 두 번째 테스트는 실패한다. 그리고 테스트 실패에 대한 이유도 알려준다.
describe('toBe', () => { test('toBe', () => { const original = { name: "foo" }; const compare = original; expect(original).toBe(compare); // <- success }); test('toBe', () => { const original = { name: "foo" }; const compare = { name: "foo" }; expect(original).toBe(compare); // <- fail - serializes to the same string }); });
toEqual()
toEqual
함수는 기본형인 경우 toBe와 같이 두 값이 같은지 비교하지만, 대상이 오브젝트인 경우 재귀적으로 프로퍼티를 비교하며 깊은 비교(Deep compare)를 수행한다.- object에 대한 비교
describe('toEqual', () => { test('success', () => { const original = { name: 'foo' }; const compare = { name: 'foo' }; expect(original).toEqual(compare); // <- success }); test('fail', () => { const original = { name: 'foo' }; const compare = { name: 'bar' }; expect(original).toEqual(compare); // <- fail }); });
original과 compare가 참조하는 오브젝트는 다르지만, 두 오브젝트 모두 name이라는 프로퍼티에 'foo'라는 값이 할당되어있기 때문에 테스트를 통과한다.
주의할 점은 다음과 같이 추가적인 프로퍼티가 있는 경우 fail이 되지만, 추가적인 프로퍼티가 undefined라면 테스트를 통과한다.
describe('toEqual', () => { test('fail', () => { const original = { name: 'foo' }; const compare = { name: 'foo', age: 27 }; expect(original).toEqual(compare); // <- fail }); test('success', () => { const original = { name: 'foo' }; const compare = { name: 'foo', age: undefined }; expect(original).toEqual(compare); // <- success }); });
이같은 동작을 고려해서 toEqual함수를 사용할 수 있도록 하자.
toStrictEqual()
toStrictEqual
은 오브젝트에 대해서 깊은 비교를 하는 것은toEqual
과 동일하지만, undefined인 프로퍼티까지 비교한다.따라서
toEqual
을 사용할때는 통과하던 똑같은 테스트가toStrictEqual
을 사용하면 실패하게 된다.- object에 대한 비교
describe('toStrictEqual', () => { test('fail', () => { const original = { name: 'foo' }; const compare = { name: 'foo', age: undefined }; expect(original).toStrictEqual(compare); // <- fail }); });
toStrictEqual
이toEqual
과 또 다른 중요한 점은 대상 오브젝트가 특정 클래스의 인스턴스인 경우, 인스턴스 타입까지 비교한다는 것이다.따라서 다음 테스트는 실패한다.
class Original { constructor(name) { this.name = name; } } describe('toStrictEqual', () => { test('fail', () => { const original = new Original('foo'); const compare = { name: 'foo' }; expect(original).toStrictEqual(compare); // <- fail }); });
toMatchObject()
toMatchObject
함수는 비교할 오브젝트가 주어진 오브젝트의 부분집합(subset)인지를 비교한다.- object에 대한 비교
describe('toMatchObject', () => { test('success', () => { const original = { name: 'foo', age: 27 }; const compare = { name: 'foo', age: 27 }; expect(original).toMatchObject(compare); // <- success }); test('success', () => { const original = { name: 'foo', age: 27 }; const compare = { name: 'foo' }; expect(original).toMatchObject(compare); // <- success }); test('fail', () => { const original = { name: 'foo' }; const compare = { name: 'foo', age: 27 }; expect(original).toMatchObject(compare); // <- fail }); });
toStrictEqual
과 같이 undefined인 프로퍼티도 검사에 포함한다.describe('toMatchObject', () => { test('fail', () => { const original = { name: 'foo' }; const compare = { name: 'foo', age: undefined }; expect(original).toMatchObject(compare); // <- fail }); });
- 배열에 대한 비교
배열에 대한 비교도 할 수 있는데, 배열의 원소가 모두 같은 경우에만 통과한다.(오브젝트가 있는 경우, 깊은 비교)
describe('toMatchObject', () => { test('success', () => { const original = [1, 2, { name: 'foo' }]; const compare = [1, 2, { name: 'foo' }]; expect(original).toMatchObject(compare); // <- success }); test('fail', () => { const original = [1, 2, 3]; const compare = [1, 2]; expect(original).toMatchObject(compare); // <- fail }); });
Conclusion
- toBe: 같은 오브젝트에 대한 참조인지(얕은 비교)
- toEqual: 같은 형태인지(깊은 비교), undefined 값 허용
- toStrictEqual: 같은 형태 & 인스턴스인지, undefined 값 허용 X
- toMatchObject: 부분집합인지, undefined 값 허용 X
object에 대해서 비교를 하는 함수들이 여러 개 존재하고, 각각의 동작과 역할이 다 다르기 때문에 Jest의 비교 함수를 사용할 때는 각 함수의 동작과 사용방법에 대한 이해를 충분히 해서 좋은 테스트 코드를 작성할 수 있도록 해야겠다.
반응형'Javascript, Typescript' 카테고리의 다른 글
[TypeORM] Entity의 constructor를 사용할 수 있을까? (2) 2022.01.13 [TS] class-validator의 활용과 검증 옵션 (0) 2022.01.03 [TypeORM] repository.save()의 동작과 upsert() (5) 2021.12.19 [TypeORM] Relation 관계에서 Join을 하는 방법들 (3) 2021.12.08 [JS] Trailing Commas에 대한 고찰 (feat.ESLint) (0) 2021.12.05