그래서 귀찮은 유닛테스트 왜 해야 하나요?
컴퓨터 프로그래밍에서 소스 코드의 특정 모듈이 의도한 대로 정확히 작동하는지 검증하는 절차라고 한다.
그 코드를 믿을만 한 건지에 대한 테스트 케이스를 작성하는 절차라는 것이다.
개발 코드를 배포하고 테스트 해보는 것은 전체 테스트라고 볼 수 있지만, 각각의 단일 함수&기능들이 정상적으로 동작되는지에 대한 불안감을 줄일 수 있다.
일단은 이 글은 유닛테스트를 왜 해야하냐의 궁금증을 해소하는 글은 아니니 이정도로 넘어가겠다.
아래 참고한 문서 및 글에 링크한 블로그를 보면 이해가 잘 될 것이다.
Simple, flexible, fun javascript test framework for Node.js & The Browser이라고 설명이 써져 있다.
하지만 Mocking도 되지 않고, jest보다 사용하는 사람이 적어서 참고할만한 코드를 찾기가 쉽지 않다.
그래서 곧 jest로 넘어갈 준비를 하고 있고, Mocha에 대한 포스팅은 아주 찬찬히 올라갈 예정이다
jest로 넘어가기 전에 궁금했던 ok, equal, strictEqual, deepStrictEqual에 대해 알아보도록 하자
Test의 value가 true인지 확인하는 것이다.
만약 value가 true가 아니라면 AssertionError가 나올거라고 설명하고 있다.
아래는 assert.ok에 대한 예제 코드이다.
import assert from 'node:assert/strict';
assert.ok(true);
// OK
assert.ok(1);
// OK
assert.ok();
// AssertionError: No value argument passed to `assert.ok()`
assert.ok(false, 'it\'s false');
// AssertionError: it's false
// In the repl:
assert.ok(typeof 123 === 'string');
// AssertionError: false == true
// In a file (e.g. test.js):
assert.ok(typeof 123 === 'string');
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(typeof 123 === 'string')
assert.ok(false);
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(false)
assert.ok(0);
// AssertionError: The expression evaluated to a falsy value:
//
// assert.ok(0)
나는 assert.ok에서 false로 나온 값이 ok인지를 확인하고 싶을 때 아래외 같이 작성하였다.
assert.ok(value === false)
// OK
assert.ok(!value)
// OK
설명으로 보면 assert.ok는 value 자체가 true인지 false인지 확인하는 것으로 보인다.
equal은 strictEqual의 lagacy 코드라고 한다.
그럼 아래 짤막한 예제와 함께 다음으로 넘어가보도록 하자
import assert from 'node:assert';
assert.equal(1, 1);
// OK, 1 == 1
assert.equal(1, '1');
// OK, 1 == '1'
assert.equal(NaN, NaN);
// OK
assert.equal(1, 2);
// AssertionError: 1 == 2
assert.equal({ a: { b: 1 } }, { a: { b: 1 } });
// AssertionError: { a: { b: 1 } } == { a: { b: 1 } }
strictEqual은 assert.strictEqual(actual, expected[,message]) 로 작성한다.
actual 과 expected 를 엄격하게 비교한다는데 도대체 엄격한 비교가 뭔지 모르겠다.
엄격한 비교란 === 와 같다고 한다.
일단 아래 짧막한 예제를 보자
import assert from 'node:assert/strict';
assert.strictEqual(1, 2);
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
//
// 1 !== 2
assert.strictEqual(1, 1);
// OK
assert.strictEqual('Hello foobar', 'Hello World!');
// AssertionError [ERR_ASSERTION]: Expected inputs to be strictly equal:
// + actual - expected
//
// + 'Hello foobar'
// - 'Hello World!'
// ^
const apples = 1;
const oranges = 2;
assert.strictEqual(apples, oranges, `apples ${apples} !== oranges ${oranges}`);
// AssertionError [ERR_ASSERTION]: apples 1 !== oranges 2
assert.strictEqual(1, '1', new TypeError('Inputs are not identical'));
// TypeError: Inputs are not identical
=== 와 == 의 차이는 후에 다시 포스팅 할 예정이다.
deepStrictEqual은 assert.deepStrictEqual(actual, expected[,message]) 로 사용할 수 있다.
== 명령어를 통한 primitive 값들의 깊은 동일성 비교를 한다고 한다.
오브젝트의 프로토타입들은 고려하지 않는다.
열거 가능한 자신의 속성만 고려되며 Error 이름과 메세지는 열거 가능한 속성이 아니더라도 항상 비교된다.
Object, Map키, Set항목은 순서 없이 비교된다.
아래 예제를 보자
import assert from 'node:assert/strict';
// This fails because 1 !== '1'.
assert.deepStrictEqual({ a: 1 }, { a: '1' });
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// {
// + a: 1
// - a: '1'
// }
// The following objects don't have own properties
const date = new Date();
const object = {};
const fakeDate = {};
Object.setPrototypeOf(fakeDate, Date.prototype);
// Different [[Prototype]]:
assert.deepStrictEqual(object, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + {}
// - Date {}
// Different type tags:
assert.deepStrictEqual(date, fakeDate);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 2018-04-26T00:49:08.604Z
// - Date {}
assert.deepStrictEqual(NaN, NaN);
// OK because Object.is(NaN, NaN) is true.
// Different unwrapped numbers:
assert.deepStrictEqual(new Number(1), new Number(2));
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + [Number: 1]
// - [Number: 2]
assert.deepStrictEqual(new String('foo'), Object('foo'));
// OK because the object and the string are identical when unwrapped.
assert.deepStrictEqual(-0, -0);
// OK
// Different zeros:
assert.deepStrictEqual(0, -0);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// + 0
// - -0
const symbol1 = Symbol();
const symbol2 = Symbol();
assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol1]: 1 });
// OK, because it is the same symbol on both objects.
assert.deepStrictEqual({ [symbol1]: 1 }, { [symbol2]: 1 });
// AssertionError [ERR_ASSERTION]: Inputs identical but not reference equal:
//
// {
// [Symbol()]: 1
// }
const weakMap1 = new WeakMap();
const weakMap2 = new WeakMap([[{}, {}]]);
const weakMap3 = new WeakMap();
weakMap3.unequal = true;
assert.deepStrictEqual(weakMap1, weakMap2);
// OK, because it is impossible to compare the entries
// Fails because weakMap3 has a property that weakMap1 does not contain:
assert.deepStrictEqual(weakMap1, weakMap3);
// AssertionError: Expected inputs to be strictly deep-equal:
// + actual - expected
//
// WeakMap {
// + [items unknown]
// - [items unknown],
// - unequal: true
// }
이번 포스팅에서는 평소 궁금했던 mocha의 ok, equal, strictEqual, deepStrictEqual에 대해 기록해보았습니다.
평소에 문서를 읽지않고 쓰던 메소드만 사용해서 유닛테스트를 해왔던 것이 부끄럽군요.
후에도 이 포스팅으로 끝나지 않고, mocha, jest, sinon등 유닛테스트 고도화를 위하여 공부하고 포스팅 할 생각입니다.
https://velog.io/@bona/테스트코드-단위테스트Unit-Test