๐Ÿงฑ Jest ๊ฐœ๋… ์ •๋ฆฌ - ๋น„๋Œ€์นญ(Asymmetric) ๋งค์ฒ˜

JS Kยท2025๋…„ 10์›” 22์ผ
post-thumbnail

์ฐธ๊ณ : Expect Reference


1) ๋น„๋Œ€์นญ(Asymmetric) ๋งค์ฒ˜๋ž€?

  • ์ผ๋ฐ˜ ๋งค์ฒ˜๋Š” expect(value).toEqual(expected)์ฒ˜๋Ÿผ ์™ผ์ชฝ(actual)์„ ๊ฒ€์‚ฌํ•œ๋‹ค.
  • ๋น„๋Œ€์นญ ๋งค์ฒ˜๋Š” expected ์ชฝ(์šฐํ•ญ)์— ๋†“์—ฌ์„œ, โ€œ๊ธฐ๋Œ€๊ฐ’์„ โ€˜์กฐ๊ฑดโ€™์œผ๋กœ ํ‘œํ˜„โ€ํ•œ๋‹ค.
  • ์ฆ‰, ์ •ํ™•ํ•œ ๊ฐ’ ๋Œ€์‹  ํƒ€์ž…/ํŒจํ„ด/์กด์žฌ์„ฑ ๊ฐ™์€ ์กฐ๊ฑด์„ ์“ด๋‹ค.
expect(getUser()).toEqual({
  id: expect.any(Number),        // โ† ๊ฐ’ ๋Œ€์‹  ์กฐ๊ฑด(ํƒ€์ž…)
  name: expect.any(String),
  email: expect.stringMatching(/@/), // โ† ํŒจํ„ด(์ •๊ทœ์‹)
});

์žฅ์ : โ€œ๊ฐ’์ด ์ •ํ™•ํžˆ X์—ฌ์•ผ ํ•œ๋‹คโ€ ๋Œ€์‹  โ€œ์ด๋Ÿฐ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋ฉด OKโ€ ํ˜•ํƒœ๋กœ ์˜๋„๋ฅผ ๋“œ๋Ÿฌ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.





2) ์ด๋ฒˆ ์ •๋ฆฌ์—์„œ ๋‹ค๋ฃฐ ๋งค์ฒ˜

  • expect.any(constructor)
  • expect.anything()
  • expect.stringContaining(substr)
  • expect.stringMatching(regexOrString)





3) ๋งค์ฒ˜๋ณ„ ๊ฐœ๋… & ์‚ฌ์šฉ ์˜ˆ์‹œ

3-1) expect.any(constructor) โ€” ํ•ด๋‹น ํƒ€์ž…์ด๋ฉด ํ†ต๊ณผ

  • Number, String, Boolean, Function, Object, Array, Date ๋“ฑ ์ƒ์„ฑ์ž ๊ฐ€๋Šฅ
  • โ€œ๊ฐ’์€ ๋ฐ”๋€” ์ˆ˜ ์žˆ์–ด๋„ ํƒ€์ž…์€ ๊ณ ์ •โ€์ผ ๋•Œ ์œ ์šฉ
test('ํƒ€์ž…๋งŒ ๋ณด์žฅ', () => {
  const user = { id: 42, name: 'Kim', createdAt: new Date() };
  expect(user).toEqual({
    id: expect.any(Number),
    name: expect.any(String),
    createdAt: expect.any(Date),
  });
});

// ๋ฐฐ์—ด ๋‚ด์—์„œ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ (๋ถ€๋ถ„์ผ์น˜ ์•„๋‹˜: ์ „์ฒด ๊ตฌ์กฐ๊ฐ€ ์ผ์น˜ํ•ด์•ผ ํ•จ)
expect([123, 'abc']).toEqual([expect.any(Number), expect.any(String)]);

๋น„๊ต ํฌ์ธํŠธ: typeof value === 'number'๋ฅผ ํ…Œ์ŠคํŠธ ๋ณธ๋ฌธ์—์„œ ๊ตณ์ด ์“ฐ์ง€ ์•Š๊ณ , ๊ฒ€์ฆ ๋ฌธ์žฅ์„ ๋ฐ์ดํ„ฐ ๋ชจ์–‘ ์˜†์— ๋ถ™์—ฌ ๊ฐ€๋…์„ฑ์„ ๋†’์ธ๋‹ค.


3-2) expect.anything() โ€” null/undefined ์ œ์™ธํ•œ ์ž„์˜์˜ ๊ฐ’์ด๋ฉด ํ†ต๊ณผ

  • โ€œ์—ฌ๊ธด ๊ฐ’์ด ์˜ค๊ธด ์™€์•ผ ํ•˜๋Š”๋ฐ, ๋ฌด์—‡์ธ์ง€๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์•„โ€ ์ƒํ™ฉ
test('์กด์žฌ์„ฑ๋งŒ ํ™•์ธ', () => {
  const res = { token: 'abc123', payload: { /* ... */ } };
  expect(res).toEqual({
    token: expect.anything(),  // null/undefined๋งŒ ์•„๋‹ˆ๋ฉด OK
    payload: expect.any(Object)
  });
});

ํŒ: ๋„คํŠธ์›Œํฌ ์‘๋‹ต์˜ id, token, requestId์ฒ˜๋Ÿผ ์žˆ๊ธฐ๋งŒ ํ•˜๋ฉด ๋˜๋Š” ํ•„๋“œ์— ์ ํ•ฉ.


3-3) expect.stringContaining(substr) โ€” ๋ฌธ์ž์—ด์— ๋ถ€๋ถ„ ๋ฌธ์ž์—ด ํฌํ•จ

  • ์ •๊ทœ์‹๋ณด๋‹ค ๋‹จ์ˆœํ•œ ๋ถ€๋ถ„ ํฌํ•จ์„ ๋น ๋ฅด๊ฒŒ ํ‘œํ˜„
test('๋ถ€๋ถ„ ๋ฌธ์ž์—ด ํฌํ•จ', () => {
  const msg = 'Hello, Jest and Testing Library!';
  expect(msg).toEqual(expect.stringContaining('Jest'));
  expect(msg).not.toEqual(expect.stringContaining('Mocha'));
});

์–ธ์ œ ์“ฐ๋‚˜: ๋ผ๋ฒจ/๋ฉ”์‹œ์ง€/๋กœ๊ทธ ๋ผ์ธ์ฒ˜๋Ÿผ โ€œ์ด ๋‹จ์–ด๋งŒ ๋“ค์–ด๊ฐ€๋ฉด ์ถฉ๋ถ„โ€ํ•œ ๊ฒ€์ฆ.


3-4) expect.stringMatching(regexOrString) โ€” ๋ฌธ์ž์—ด์ด ํŒจํ„ด์— ๋งค์นญ

  • ์ •๊ทœ์‹ ๋˜๋Š” ๋ฌธ์ž์—ด์„ ๋ฐ›์•„ ํŒจํ„ด ์ผ์น˜ ๊ฒ€์‚ฌ
  • stringContaining๋ณด๋‹ค ํ‘œํ˜„๋ ฅ์ด ๋” ํ’๋ถ€
test('์ •๊ทœ์‹ ํŒจํ„ด ์ผ์น˜', () => {
  const code = 'user-001';
  expect(code).toEqual(expect.stringMatching(/^user-\d+$/));

  const email = 'dev@ex.com';
  expect(email).toEqual(expect.stringMatching(/.+@.+\..+/));
});

์–ธ์ œ ์“ฐ๋‚˜: ์•„์ด๋”” ํฌ๋งท, ๋ฒ„์ „ ๋ฌธ์ž์—ด, ๋‚ ์งœ/์‹œ๊ฐ„ ํฌ๋งท ๋“ฑ ํ˜•์‹์„ ๊ฒ€์ฆํ•  ๋•Œ.


4) ์กฐํ•ฉ ์˜ˆ์‹œ (๋ถ€๋ถ„์ผ์น˜ ์—†์ด๋„ ์ถฉ๋ถ„ํžˆ ๊ฐ•๋ ฅ)

const makeOrder = () => ({
  orderId: 'ORD-2025-0001',
  buyer: { id: 7, name: 'Lee' },
  items: [
    { sku: 'A-01', qty: 2 },
    { sku: 'B-99', qty: 1 },
  ],
  createdAt: new Date().toISOString(),
});

test('์ฃผ๋ฌธ ๊ฐ์ฒด์˜ ํƒ€์ž…/ํŒจํ„ด๋งŒ ๋ณด์žฅ (๋ถ€๋ถ„์ผ์น˜ ๋ฏธ์‚ฌ์šฉ)', () => {
  const order = makeOrder();
  expect(order).toEqual({
    orderId: expect.stringMatching(/^ORD-\d{4}-\d{4}$/),
    buyer: {
      id: expect.any(Number),
      name: expect.any(String),
    },
    items: [
      { sku: expect.any(String), qty: expect.any(Number) },
      { sku: expect.any(String), qty: expect.any(Number) },
    ],
    createdAt: expect.any(String), // ISO ๋ฌธ์ž์—ด์ด๋ผ๊ณ  ๊ฐ€์ • (๋” ์—„๊ฒฉํžˆ ํ•˜๋ ค๋ฉด ์ •๊ทœ์‹ ์‚ฌ์šฉ)
  });
});

ํฌ์ธํŠธ: ์ „์ฒด ๊ตฌ์กฐ๋Š” ๊ทธ๋Œ€๋กœ ๋‘๊ณ , ๋‚ด๋ถ€ ๊ฐ’๋“ค๋งŒ ํƒ€์ž…/ํŒจํ„ด์œผ๋กœ ์œ ์—ฐํ•˜๊ฒŒ ํ‘œํ˜„.
๋ฐฐ์—ด๋„ ์ •ํ™•ํžˆ ๊ทธ ๊ธธ์ด/์ˆœ์„œ๋ฅผ ๊ธฐ๋Œ€ํ•œ๋‹ค๋ฉด ์ด๋ ‡๊ฒŒ ์“ฐ๋ฉด ๋œ๋‹ค(๋ถ€๋ถ„์ผ์น˜ ์•„๋‹˜).





5) ํ”ํ•œ ์˜คํ•ด & ์ฃผ์˜

  • expect.any(Number)๋Š” ํƒ€์ž…๋งŒ ๋ณธ๋‹ค. ๊ตฌ๊ฐ„/๋ฒ”์œ„ ๊ฒ€์‚ฌ๋Š” toBeGreaterThan/toBeCloseTo ๋“ฑ ์ˆซ์ž ๋งค์ฒ˜๋ฅผ ํ™œ์šฉ.
  • expect.anything()์€ null/undefined๋งŒ ๊ฑฐ๋ฅธ๋‹ค. ๋นˆ ๋ฌธ์ž์—ด ''์ด๋‚˜ 0์€ ํ—ˆ์šฉ๋œ๋‹ค๋Š” ์  ์ฃผ์˜.
  • stringContaining/stringMatching์€ ์šฐํ•ญ์—๋งŒ ์“ด๋‹ค. ์ฆ‰, toEqual(์—ฌ๊ธฐ)์˜ expected ์ชฝ.





6) ๋ฏธ๋‹ˆ ์น˜ํŠธ์‹œํŠธ

๋งค์ฒ˜ํ•ต์‹ฌ์˜ˆ์‹œ
expect.any(Ctor)ํƒ€์ž…๋งŒ ๋ณด์žฅ{ id: expect.any(Number) }
expect.anything()์กด์žฌ์„ฑ๋งŒ ๋ณด์žฅ(null/undefined ์ œ์™ธ){ token: expect.anything() }
expect.stringContaining(substr)๋ถ€๋ถ„ ๋ฌธ์ž์—ด ํฌํ•จexpect(str).toEqual(expect.stringContaining('Jest'))
expect.stringMatching(re)์ •๊ทœ์‹/๋ฌธ์ž์—ด ํŒจํ„ด ์ผ์น˜expect(code).toEqual(expect.stringMatching(/^ID-\d+$/))

profile
1.01^365

0๊ฐœ์˜ ๋Œ“๊ธ€