Jest: ๊ธฐ๋Œ€์— ๋Œ€ํ•œ ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ปจํ…์ŠคํŠธ

์— ๋งŒ๋“  2016๋…„ 10์›” 21์ผ  ยท  76์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: facebook/jest

๋‹จ์ผ it ์— ์—ฌ๋Ÿฌ ๊ธฐ๋Œ€์น˜๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ํ˜„์žฌ ์ฝ”๋“œ์˜ ์ค„ ๋ฒˆํ˜ธ์™€ ์‹คํŒจ๋ฅผ ์ƒํ˜ธ ์ฐธ์กฐํ•˜์ง€ ์•Š๊ณ  ์‹ค์ œ๋กœ ์‹คํŒจํ•œ ๊ธฐ๋Œ€์น˜๋ฅผ ํŒŒ์•…ํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

test('api works', () => {
    expect(api()).toEqual([]) // api without magic provides no items
    expect(api(0)).toEqual([]) // api with zero magic also provides no items
    expect(api(true)).toEqual([1,2,3]) // api with magic enabled provides all items
})

์–ด๋–ค ๊ธฐ๋Œ€๊ฐ€ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๊นŒ? ์ฒซ ๋ฒˆ์งธ ๋˜๋Š” ๋‘ ๋ฒˆ์งธ?

image

์Šคํƒ ์ถ”์ ์˜ ๋งจ ์œ„์—์„œ ์ค„ ๋ฒˆํ˜ธ๋ฅผ ์ฐพ์•„ ๋‹ค์‹œ ๋งคํ•‘ํ•˜์ง€ ์•Š๊ณ ๋„ ์–ด๋–ค ๊ธฐ๋Œ€๊ฐ€ ์‹คํŒจํ–ˆ๊ณ  ๊ธฐ๋Œ€ ์ถœ๋ ฅ์ด ์‹ค์ œ๋กœ ์ธ๊ฐ„์˜ ๊ด€์ ์—์„œ ์˜๋ฏธํ•˜๋Š”์ง€ ์ฆ‰์‹œ ๋ช…ํ™•ํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•”ํ˜ธ.


์•„๋ž˜์—์„œ tape ์— ํ•ด๋‹นํ•˜๋Š” ํ•ญ๋ชฉ์„ ๋น„๊ตํ•˜์‹ญ์‹œ์˜ค. ์ฒซ ๋ฒˆ์งธ ์–ด์„ค์…˜ ์‹คํŒจ ํ›„ ํ…Œ์ดํ”„๊ฐ€ ๋ณต๊ตฌ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์„ ๋ฌด์‹œํ•˜์‹ญ์‹œ์˜ค. tape ๋Š” ๊ฐ ์˜ˆ์ƒ ์‹คํŒจ ์œ„์— ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ์ธ์‡„ํ•˜์—ฌ ํ…Œ์ŠคํŠธ ํŒŒ์ผ๋กœ ๋Œ์•„๊ฐ€์ง€ ์•Š๊ณ ๋„ ์–ด๋–ค ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ–ˆ๋Š”์ง€ ์ •ํ™•ํžˆ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋˜ํ•œ ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๋…ธ์ด์ฆˆ๋ฅผ ํ…Œ์ŠคํŠธ ์†Œ์Šค์˜ ์ค„ ๋์œผ๋กœ ๋ฐ€์–ด๋‚ด์–ด ์–ด์จŒ๋“  ์ฃผ์„์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

test('api works', t => {
  t.deepEquals(api(), [], 'api without magic provides no items')
  t.deepEquals(api(0), [], 'api with zero magic also provides no items')
  t.deepEquals(api(true), [1,2,3], 'api with magic enabled provides all items')
})

image


jest ์˜ค๋ฅ˜์— ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ •๋ณด๋ฅผ ์ฒจ๋ถ€ํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์žฅํ™ฉํ•œ IMO์ธ ์ถ”๊ฐ€ it ์— ๋ชจ๋“  ๊ฒƒ์„ ๋ž˜ํ•‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

describe('api works', () => {
  test('api without magic provides no items', () => {
    expect(api()).toEqual([])
  })
  test('api with zero magic also provides no items', () => {
    expect(api(0)).toEqual([])
  })
  test('api with magic enabled provides all items', () => {
    expect(api(true)).toEqual([1,2,3])
  })
})

์ด์ƒ์ ์œผ๋กœ๋Š” ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ expect ๋์— ์–ด๋–ป๊ฒŒ๋“  ์ฒจ๋ถ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ

์–ด์„ค์…˜ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ์„œ์˜ ์ปจํ…์ŠคํŠธ ๋ฉ”์‹œ์ง€:

test('api works', () => {
    expect(api()).toEqual([], 'api without magic provides no items')
    expect(api(0)).toEqual([], 'api with zero magic provides no items')
    expect(api(true)).toEqual([1,2,3], 'api with magic enabled provides all items')
})


๋˜๋Š” ์—ฐ๊ฒฐ๋œ .because ๋˜๋Š” .why ๋˜๋Š” .comment ๋˜๋Š” .t ๋˜๋Š” ๊ธฐํƒ€์™€ ๊ฐ™์€ ์ปจํ…์ŠคํŠธ ๋ฉ”์‹œ์ง€:

test('api works', () => {
    expect(api()).toEqual([]).because('api without magic provides no items')
    expect(api(0)).toEqual([]).because('api with zero magic provides no items')
    expect(api(true)).toEqual([1,2,3]).because('api with magic enabled provides all items')
})

๋˜๋Š” jest๊ฐ€ ๋‹จ์ˆœํžˆ ํŒŒ์ผ์„ ์ฝ๊ณ  ๊ธฐ๋Œ€ ์ž์ฒด๊ฐ€ ์žˆ๋Š” ์‹ค์ œ ์†Œ์Šค ์ฝ”๋“œ ๋ผ์ธ์„ ์ธ์‡„ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋” ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์ด ํ† ๋ก  ๊ณผ ์ด ์ €์žฅ์†Œ ์—์„œ ๋ฉ‹์ง€๊ณ  ์˜๋ฏธ ์žˆ๋Š” ์ €์žฅ์†Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

it('has all the methods', () => {
  since('cookie is a method').expect(reply.cookie).toBeDefined();
  since('download is a method').expect(reply.download).toBeDefined();
  since('end is a method').expect(reply.end).toBeDefined();
  // ...
});

์‚ฌ์šฉ๋ฒ•์€ because ์™€ ๋น„์Šทํ•˜์ง€๋งŒ ์˜๋ฏธ์ƒ ๋” ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹น์‹ ์ด ์ด๊ฒƒ์„ ์ข‹์•„ํ•œ๋‹ค๋ฉด ๋‚˜๋Š” since ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” PR์„ ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ชจ๋“  76 ๋Œ“๊ธ€

์•ผ! ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ์‹ค์ œ๋กœ Jasmine์— ์ด๊ฒƒ์„ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ์ง€๋งŒ FB์—์„œ ์ˆ˜์ฒœ ๊ฐœ์˜ ํ…Œ์ŠคํŠธ ํŒŒ์ผ์ด ์žˆ์ง€๋งŒ ์•„๋ฌด๋„ ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ง€๊ธˆ ์šฐ๋ฆฌ๋Š” ๋Œ€๋žต์ ์ธ ์ •๋ณด์™€ ์˜ˆ์ƒ์œผ๋กœ ์ด์–ด์ง€๋Š” ์Šคํƒ ์ถ”์ ์ด ํฌํ•จ๋œ ๋ฉ‹์ง„ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ธ์‡„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(์Šคํฌ๋ฆฐ์ƒท์—์„œ์™€ ๊ฐ™์ด). ๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋˜์ง€๋Š” ์ค„์„ ์ธ์‡„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜์ง€๋งŒ ์ข…์ข… ์ฃผ์žฅ์ด ์—ฌ๋Ÿฌ ์ค„๋กœ ๊ธธ์–ด์ง‘๋‹ˆ๋‹ค.

expect(a).toEqual({
  โ€ฆ
});

๊ทธ๋ž˜์„œ ์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ๊ทธ๋ ‡๊ฒŒ ์ข‹์•„ ๋ณด์ด์ง€ ์•Š์„ ๊ฒƒ์ด๊ณ  ํŒŒ์„œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ JS๋ฅผ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๊ณ  ๊ด€๋ จ ์ •๋ณด๋ฅผ ์ถ”์ถœํ•˜๊ฑฐ๋‚˜(๊ธด ์ค„์„ ์ถ•์†Œ) ๋ณด๊ธฐ ์ข‹๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ด์™€ ์œ ์‚ฌํ•œ ๊ฒƒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ฐœ์ธ์ ์œผ๋กœ ํ˜„์žฌ๋กœ์„œ๋Š” ์ถฉ๋ถ„ํ•œ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์žฌ๊ณ ํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค. ๊ทธ๋‹ค์ง€ ๋ณต์žกํ•˜์ง€ ์•Š์ง€๋งŒ ๋ฌธ์ œ๋ฅผ ๋” ๋นจ๋ฆฌ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์œผ๋ฉด ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

์šฐ๋ฆฌ๋Š” ์‹ค์ œ๋กœ Jasmine์— ์ด๊ฒƒ์„ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ์ง€๋งŒ FB์—์„œ ์ˆ˜์ฒœ ๊ฐœ์˜ ํ…Œ์ŠคํŠธ ํŒŒ์ผ์ด ์žˆ์ง€๋งŒ ์•„๋ฌด๋„ ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

@cpojer ๊ทธ๋ž˜์„œ ํŒจํ„ด์€ it ์—์„œ ๊ฐ ์ฃผ์žฅ์„ ๋ž˜ํ•‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๊นŒ? ๋ฐ/๋˜๋Š” ํ–‰ ๋ฒˆํ˜ธ๋ฅผ ์‹ ๋ขฐํ•ฉ๋‹ˆ๊นŒ?

์ด ํŒจํ„ด์ด ๋” ์ข‹๊ฑฐ๋‚˜ ๋‚˜์˜๊ธฐ ๋•Œ๋ฌธ์— ๋œ ์ฑ„ํƒ๋˜์—ˆ์ง€๋งŒ ๊ธฐ์กด ํ…Œ์ŠคํŠธ์™€์˜ ์ผ๊ด€์„ฑ์„ ์œ„ํ•ด ๋” ๋งŽ์ด ์ฑ„ํƒ๋˜์—ˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๋˜๋Š” ๊ธฐ๋Šฅ์˜ ์กด์žฌ๋ฅผ ๋ชจ๋ฅด์‹ญ๋‹ˆ๊นŒ? ์ด๊ฒƒ์ด ์ž์Šค๋ฏผ์— ์žˆ๋Š”์ง€ ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋˜์ง€๋Š” ์ค„์„ ์ธ์‡„ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜์ง€๋งŒ ์ข…์ข… ์ฃผ์žฅ์ด ์—ฌ๋Ÿฌ ์ค„๋กœ ๊ธธ์–ด์ง‘๋‹ˆ๋‹ค.

ํ•œ ์ค„๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜๋ฉด ์–ด์„ค์…˜์— ๋” ๋งŽ์€ ์˜๋ฏธ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์•„๋งˆ๋„?

const adminUser = {
  โ€ฆ
}
expect(a).toEqual(adminUser);

๊ฐœ์ธ์ ์œผ๋กœ ํ˜„์žฌ๋กœ์„œ๋Š” ์ถฉ๋ถ„ํ•œ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์žฌ๊ณ ํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

์œ„์˜ ์˜ˆ๋Š” ๋ชจ๋“  ๊ฒƒ์— ์žฅํ™ฉํ•œ(IMO) ๋ž˜ํผ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š” ํ•œ ์–ด๋–ค ์–ด์„ค์…˜์ด ์‹คํŒจํ–ˆ๋Š”์ง€ ์ •ํ™•ํžˆ ๋ฐœ๊ฒฌํ•˜๊ธฐ ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์†Œ์Šค๋งต ํ–‰ ๋ฒˆํ˜ธ๊ฐ€ ํ•ญ์ƒ ์ •ํ™•ํ•˜์ง€ ์•Š์€ ํŠธ๋žœ์ŠคํŒŒ์ผ ํ™˜๊ฒฝ์—์„œ ํŠนํžˆ ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค. ๊ฐ„๊ฒฐํ•œ ํ…Œ์ŠคํŠธ์ฒ˜๋Ÿผ ๋น ๋ฅด๊ณ  ์ •ํ™•ํ•˜๊ฒŒ ์ดํ•ด๊ฐ€ ๊นจ์ง€๊ณ  ์–ด๋””๊ฐ€ ์ค‘์š”ํ•œ์ง€ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋‹ค์ง€ ๋ณต์žกํ•˜์ง€ ์•Š์ง€๋งŒ ๋ฌธ์ œ๋ฅผ ๋” ๋นจ๋ฆฌ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์œผ๋ฉด ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

์œ„์—์„œ ๋ช‡ ๊ฐ€์ง€ ์ œ์•ˆ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋” ๊ฐ„๋‹จํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๊ฒƒ์„ ์ฐพ๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์•ˆ๋…•ํ•˜์„ธ์š” @timoxley์ž…๋‹ˆ๋‹ค! ์šฐ๋ฆฌ๋Š” ์ด๋ฏธ ์ด์™€ ๊ฐ™์€ ๊ฒƒ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ฒซ ๋ฒˆ์งธ ์˜ต์…˜์˜ ๋ฌธ์ œ๋Š” ์ผ๋ถ€ ๋งค์ฒ˜์— ์„ ํƒ์  ์ธ์ˆ˜๊ฐ€ ์žˆ์–ด ์ƒํ™ฉ์ด ๋” ๋ณต์žกํ•ด์ง„๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์—ฌ๊ธฐ ๋‘ ๋ฒˆ์งธ ๊ฒฝ์šฐ์—๋Š” ์ธ์ˆ˜๊ฐ€ ๊ทผ์ ‘์„ฑ์ธ์ง€ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์ธ์ง€ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

expect(555).toBeCloseTo(111, 2, 'reason why');
expect(555).toBeCloseTo(111, 'reason why');

๋ฌด์–ธ๊ฐ€๊ฐ€ ๊ธฐ๋Œ€๋ฅผ ์ถฉ์กฑํ•˜์ง€ ๋ชปํ•˜๋Š” ์ฆ‰์‹œ match๊ฐ€ ๋˜์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋‘ ๋ฒˆ์งธ ์ œ์•ˆ์€ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

expect(1).toBe(2)/* will throw here */.because('reason');

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งค์ฒ˜๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์ด์œ ๋ฅผ ์ฒจ๋ถ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

expect(1).because('reason').toBe(2);
// or 
because('reason').expect(1).toBe(2);

ํ•˜์ง€๋งŒ ์ด API๋Š” ๊ทธ๋‹ค์ง€ ์ข‹์•„ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์˜ต์…˜์€ expect ์— ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

expect(1, 'just because').toBe(2);

๊ทธ๋Ÿฌ๋‚˜ ์ด์ „ ์˜ต์…˜๊ณผ ๊ฑฐ์˜ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ๋ณ„๋กœ ์œ ์šฉํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ์ด์œ ๋Š” ์—”์ง€๋‹ˆ์–ด๊ฐ€ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์— ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ณ  ์‹ถ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋“ค์„ ๋” ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๊ฐ€ ํ•˜๋Š” ๋ชจ๋“  ์ผ์€ ๋” ๋‚˜์œ ํ…Œ์ŠคํŠธ๋กœ ์ด์–ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ณผ๊ฑฐ์—๋Š” ์‹ค์ œ๋กœ ์‚ฌ์šฉ์ž ์ง€์ • ๋งค์ฒ˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์€ ์†”๋ฃจ์…˜์ด์—ˆ์Šต๋‹ˆ๋‹ค. Jest์˜ ๋‹ค์Œ ๋ฒ„์ „์—์„œ expect.extend ๋ฅผ ์†Œ๊ฐœํ•  ์˜ˆ์ •์ด๋ฉฐ ์ด๋ฅผ ํ†ตํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋งค์ฒ˜๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

expect(a).toEqualMySpecificThing(โ€ฆ)

์ด๋ฅผ ํ†ตํ•ด ๋ณด๋‹ค ํ‘œํ˜„์ ์ธ ์‹คํŒจ ๋ฉ”์‹œ์ง€๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์ด Relay์™€ ๊ฐ™์€ ํ”„๋กœ์ ํŠธ์—์„œ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๋งค์ฒ˜ ๋ณด๊ธฐ: https://github.com/facebook/relay/blob/master/src/tools/__mocks__/RelayTestUtils.js#L281

ํ™œ๋™์ด ์—†์–ด ๋ฌธ์„ ๋‹ซ์ง€๋งŒ ์ข‹์€ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์œผ๋ฉด ๋‹ค์‹œ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@cpojer @dmitriiabramov ์ง€์—ฐ์— ๋Œ€ํ•ด ์‚ฌ๊ณผ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

expect ์— ๋Œ€ํ•œ ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜ ๋˜๋Š” .because ๋กœ ์ด์œ ๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ฑฐ๋‚˜ ํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด ๋ฌด์—‡์„ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

์—”์ง€๋‹ˆ์–ด๋Š” ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์— ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@cpojer ๋™์˜ํ•ฉ๋‹ˆ๋‹ค! ํ…Œ์ŠคํŠธ ๋””๋ฒ„๊น…์— ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์€ ๊ฒƒ ์™ธ์—๋„ ์ด๊ฒƒ์ด ๋” ๋งŽ์€ ์‹คํŒจ ์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ๋Š” ๋œ ์žฅํ™ฉํ•œ API๊ฐ€ ๋” ๋ฐ”๋žŒ์งํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๋ฐ”๋กœ ๊ทธ ์ด์œ ์ž…๋‹ˆ๋‹ค.

์ผ๋ถ€ ๊ตฌ์ฒด์ ์ธ ์ˆซ์ž์˜ ๊ฒฝ์šฐ ์œ„์˜ ๋‚ด ์„ค๋ช…์— ์žˆ๋Š” ๊ฐ„๋‹จํ•œ ์˜ˆ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ดํ”„๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™๋“ฑํ•œ ์ฃผ์žฅ + ์ปจํ…์ŠคํŠธ๋ฅผ ์–ป์œผ๋ ค๋ฉด Jest๋Š” ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ ์˜์‹์šฉ ์ƒ์šฉ๊ตฌ ์–‘์˜ ๊ฑฐ์˜ ๋‘ ๋ฐฐ๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • 1.8๋ฐฐ ๋ผ์ธ(6 ๋Œ€ 11)
  • 2๋ฐฐ ๋“ค์—ฌ์“ฐ๊ธฐ(1 ๋Œ€ 2)
  • 2x ๊ด„ํ˜ธ/๊ณฑ์Šฌ(24 ๋Œ€ 48) !

์ด๊ฒƒ์€ ๊ฐœ์„ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

// tape
test('api works', t => {
  t.deepEquals(api(), [], 'api without magic provides no items')
  t.deepEquals(api(0), [], 'api with zero magic also provides no items')
  t.deepEquals(api(true), [1,2,3], 'api with magic enabled provides all items')
  t.end()
})

// jest
describe('api works', () => {
  test('api without magic provides no items', () => {
    expect(api()).toEqual([])
  })
  test('api with zero magic also provides no items', () => {
    expect(api(0)).toEqual([])
  })
  test('api with magic enabled provides all items', () => {
    expect(api(true)).toEqual([1,2,3])
  })
})

์—…๋ฐ์ดํŠธ : ํ™”์‚ดํ‘œ๊ฐ€ ์žˆ๋Š” ํ•œ ์ค„์— ๋†๋‹ด ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.

// jest
describe('api works', () => {
  test('api without magic provides no items', () => expect(api()).toEqual([]))
  test('api with zero magic also provides no items', () => expect(api(0)).toEqual([]))
  test('api with magic enabled provides all items', () => expect(api(true)).toEqual([1,2,3]))
})

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ค„์ด ๋” ๊ธธ์–ด์ง€์ง€๋งŒ ์ด์ „์— ๋น„๊ตํ•œ ํ†ต๊ณ„๊ฐ€ ๋‹ค์†Œ ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

  • 0.8x ๋ผ์ธ(6 ๋Œ€ 5)
  • 1x ๋“ค์—ฌ์“ฐ๊ธฐ(1 ๋Œ€ 1)
  • 1.75x ๊ด„ํ˜ธ/๊ณฑ์Šฌ(24 ๋Œ€ 42)

๊ทธ๋Ÿฌ๋‚˜ ์ค„ ๋ฐ”๊ฟˆ ์—†์ด ์ค„ ์‹œ์ž‘ ๋ถ€๋ถ„์— ํ…Œ์ŠคํŠธ ์„ค๋ช…์ด ์žˆ์œผ๋ฉด ํ…Œ์ŠคํŠธ์˜ "ํ•ต์‹ฌ", ์ฆ‰ ์‹ค์ œ ์–ด์„ค์…˜์„ ์ž„์˜์˜ ์—ด ์œ„์น˜์— ๋ฐฐ์น˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋…ผ๋ฆฌ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค.

์ฝ”๋“œ๋ฅผ ํŒŒ์‹ฑํ•˜๋Š” ๊ฒƒ์€ ํ…Œ์ŠคํŠธ ์„ค๋ช…์„ ์ฝ๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฐฌ์‚ฌ๋ฅผ ๋ฐ›๋Š” ์„ค๋ช…์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ํ–‰์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์— ์•„๋ฌด๋„ ์ฃผ์„์„ ์“ฐ์ง€ ์•Š๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด๊ฒƒ์€ ์‚ฌ๋„๋งˆ์กฐํžˆ์ฆ˜์  ๊ด‘๊ธฐ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค:

/* api without magic provides no items */ expect(api()).toEqual([])
/* api with zero magic also provides no items */ expect(api(0)).toEqual([])
/* api with magic enabled provides all items */ expect(api(true)).toEqual([1,2,3])

์ด์ƒ์ ์œผ๋กœ๋Š” ๋ชจ๋“  ์–ด์„ค์…˜ ์ฝ”๋“œ๊ฐ€ ๋™์ผํ•œ ์—ด์— ๊น”๋”ํ•˜๊ฒŒ ์ •๋ ฌ๋˜์–ด ์‚ฌ๋žŒ์ด ์‰ฝ๊ฒŒ ๊ตฌ๋ฌธ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ƒ๊ฐ์„ ๋ฐ”ํƒ•์œผ๋กœ expect ์— ๋Œ€ํ•œ ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜์˜ ๋Œ€์•ˆ ์ œ์•ˆ๋ณด๋‹ค๋Š” ํ›„ํ–‰ .because ํ˜•์‹์„ ๊ฐ•๋ ฅํ•˜๊ฒŒ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

๋Œ€ํ™”๋ฅผ ๊ณ„์†ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์„ค๋ช… ๋ธ”๋ก์ด ํ•„์š”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ๋” ์ž‘๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. .because ๋Š” ๋ถˆํ–‰ํžˆ๋„ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด matcher๊ฐ€ ๋˜์งˆ ๋•Œ( .because ๊ฐ€ ํ˜ธ์ถœ๋˜๊ธฐ ์ „์— ๋ฐœ์ƒํ•จ), ์ด๋ฆ„์„ ์ถ”์ถœํ•  ๋ฐฉ๋ฒ•์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ๊ฐ ๋งค์ฒ˜ ํ•จ์ˆ˜์˜ ๋งˆ์ง€๋ง‰ ์ธ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

expect ์˜ ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
๋ชจํ˜ธ์„ฑ ๋•Œ๋ฌธ์— ๋ชจ๋“  ๋งค์ฒ˜ ํ•จ์ˆ˜์˜ ๋งˆ์ง€๋ง‰ ์ธ์ˆ˜๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
์˜ˆ

expect(obj).toHaveProperty('a.b.c', 'is that a reason or a value of the property?');

ํ™œ๋™์ด ์—†์–ด ๋ฌธ์„ ๋‹ซ์ง€๋งŒ ์ข‹์€ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์œผ๋ฉด ๋‹ค์‹œ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@cpojer expect(value).toBe(something, 'because message') ์˜ ์žฌ์Šค๋ฏผ(๋ฐ ๊ธฐํƒ€) ๋ฐฉ์‹์ด ๋ฐฐ์ œ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๊ฐ€ ๋ถˆ๋ถ„๋ช…ํ•ฉ๋‹ˆ๊นŒ?

ํ•œ ๊ฐ€์ง€ ์˜ˆ๋Š” ์ƒํƒœ ๋จธ์‹ ์„ ํ…Œ์ŠคํŠธํ•˜๋Š” redux-saga/redux-observable ํ•ญ๋ชฉ์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์–ด๋–ค ์ƒํƒœ์—์„œ ์‹คํŒจํ–ˆ๋Š”์ง€์— ๋Œ€ํ•œ ์„ค๋ช… ๋ฉ”์‹œ์ง€๊ฐ€ ์žˆ์œผ๋ฉด ๋งค์šฐ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ € ์˜ˆ์‹œ๋Š” ์ธ์œ„์ ์ธ๊ฑฐ๋ผ ์„ค๋ช…๋„ ๊ทธ๋ ‡๊ณ ..

@jayphelps ๋ชจ๋“  ์žฌ์Šค๋ฏผ ๋งค์ฒ˜๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋” ์ด์ƒ ์žฌ์Šค๋ฏผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@dmitriiabramov ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์ œ ์งˆ๋ฌธ์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์žฌ์Šค๋ฏผ _way_ ๊ทธ๊ฒƒ์„ ๋‹ค์‹œ ์ถ”๊ฐ€ํ•˜๋„๋ก ํŒ๊ฒฐ์„ ๋ฐ›์•˜์Šต๋‹ˆ๊นŒ? ๊ทธ๋“ค์ด ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ์ผ์„ ํ•ฉ๋‹ˆ๋‹ค.

@jayphelps ์ „์— ๋งํ–ˆ๋“ฏ์ด ๋ชจํ˜ธ์„ฑ ๋•Œ๋ฌธ์— ๋ชจ๋“  ๋งค์ฒ˜์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

expect(obj).toHaveProperty('a.b.c', 'is that a reason or a value of the property?');

๋…ธ๋ž˜ jest matchers๋Š” ํƒ€์‚ฌ ํŒจํ‚ค์ง€๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ธ์ˆ˜ ๋ชฉ๋ก์„ ์—‰๋ง์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ์ข‹์€ ์ƒ๊ฐ์ด ์•„๋‹™๋‹ˆ๋‹ค.

๊ฐ€์žฅ ๊น”๋”ํ•œ ์˜ต์…˜์€ expect ์˜ ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ•ญ์ƒ ์ •ํ™•ํžˆ ํ•˜๋‚˜์˜ ์ธ์ˆ˜๋ฅผ ์ทจํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

expect(123, 'jest because').toEqual(123);

๊ทธ๋ž˜๋„ API๋ฅผ ์˜ค๋ฒ„๋กœ๋“œํ•˜๊ณ  ์‹ถ์€์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ํŽ˜์ด์Šค๋ถ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ์—์„œ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์œผ๋ฉฐ ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ์—๋Š” ์ƒˆ ํ…Œ์ŠคํŠธ๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

beforeEach(someSharedSetup);
test('reason or description', () => expect(1).toBe(1));

๋ช‡ ์ค„๋งŒ ๋”ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค :)

๋˜๋Š” ๋‹ค๋ฅธ describe() ํ˜ธ์ถœ์— ๋„ฃ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

@dmitriiabramov ์„ฑ๊ฐ€์‹  ๊ฒฝ์šฐ๋Š” ์‚ฌ๊ฐ€, ์„œ์‚ฌ์‹œ ๋“ฑ์˜ ์ƒํƒœ ๋จธ์‹ ์—์„œ์™€ ๊ฐ™์ด ์ƒํƒœ๋ฅผ ๊ตฌ์ถ•ํ•  ๋•Œ์ž…๋‹ˆ๋‹ค. ๊ฐ ํ…Œ์ŠคํŠธ์—๋Š” ์ด์ „ ์ƒํƒœ ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•˜๋ฉฐ, ์ด๋ฅผ ๋ถ„๋ฆฌํ•˜๋ ค๋ฉด AFAIK ์ด๋“ ์—†์ด ์—„์ฒญ๋‚œ ์–‘์˜ ๋ณต์ œ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

it('stuff', () => {
  const generator = incrementAsync();

  expect(generator.next().value).toBe(
    call(delay, 1000)
  );

  expect(generator.next().value).toBe(
    put({ type: 'INCREMENT' })
  );

  expect(generator.next()).toBe(
    { done: true, value: undefined }
  );
});

๋˜๋Š” ๋‹ค๋ฅธ describe() ํ˜ธ์ถœ์— ๋„ฃ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ ์ž์„ธํžˆ ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์ค‘์ฒฉ ์„ค๋ช… ํ˜ธ์ถœ AFAIK๋Š” ์„น์…˜ ์ œ๋ชฉ์„ ๋‚˜๋ˆ„๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด์—ˆ๊ณ  ํ…Œ์ŠคํŠธ๋Š” ์—ฌ์ „ํžˆ ๋™์‹œ์— ์‹คํ–‰๋ฉ๋‹ˆ๊นŒ?

ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ(ํŒŒ์ผ)๋Š” ๋™์‹œ์— ์‹คํ–‰๋˜์ง€๋งŒ test() ํ˜ธ์ถœ์€ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ์ƒ๊ฐํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

test('111' () => {
  jest.debug('write something only if it fails');
  expect(1).toBe(2);
});

์ผ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

์ด ํ† ๋ก  ๊ณผ ์ด ์ €์žฅ์†Œ ์—์„œ ๋ฉ‹์ง€๊ณ  ์˜๋ฏธ ์žˆ๋Š” ์ €์žฅ์†Œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

it('has all the methods', () => {
  since('cookie is a method').expect(reply.cookie).toBeDefined();
  since('download is a method').expect(reply.download).toBeDefined();
  since('end is a method').expect(reply.end).toBeDefined();
  // ...
});

์‚ฌ์šฉ๋ฒ•์€ because ์™€ ๋น„์Šทํ•˜์ง€๋งŒ ์˜๋ฏธ์ƒ ๋” ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹น์‹ ์ด ์ด๊ฒƒ์„ ์ข‹์•„ํ•œ๋‹ค๋ฉด ๋‚˜๋Š” since ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋Š” PR์„ ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์‰ฌ์šด ๋ฐฉ๋ฒ•์„ ๊ตฌํ˜„ํ•˜์‹ญ์‹œ์˜ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์ž์ฃผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์ง€๋งŒ ํŠนํžˆ ๋” ๋ณต์žกํ•œ ํ…Œ์ŠคํŠธ์˜ ๊ฒฝ์šฐ ํŒŒ๊ณ ๋“ค์ง€ ์•Š๊ณ ๋„ ๋ฌด์—‡์ด ์‹คํŒจํ•˜๋Š”์ง€ ์ •ํ™•ํžˆ ์•„๋Š” ๊ฒƒ์ด ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

"ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ๋ฅผ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ๋‹ค์‹œ ์ž‘์„ฑํ•˜์‹ญ์‹œ์˜ค"๋ผ๊ณ  ๋งํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์—”์ง€๋‹ˆ์–ด๊ฐ€ _writing_ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ๋ณด๋‹ค ๋” ์‹ซ์–ดํ•˜๋Š” ์œ ์ผํ•œ ๊ฒƒ์€ _rewriting_ ํ…Œ์ŠคํŠธ ์Šค์œ„ํŠธ์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์–ด๋””์„ ๊ฐ€ ๋ณธ ๋˜ ๋‹ค๋ฅธ ์ œ์•ˆ์€ ์ด๊ฒƒ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์ด์œ ์— ๋Œ€ํ•œ ์„ค๋ช…๊ณผ ํ•จ๊ป˜ ์ด ๋™์ผํ•œ ๋ฌธ์ œ์˜ ์œ„์น˜๋ฅผ โ€‹โ€‹์žŠ์–ด๋ฒ„๋ ธ์Šต๋‹ˆ๋‹ค . ์ข€ ์ž์•ผ๊ฒ ๋„ค์š” :)

๊ฐ„๋‹จํ•œ "ํ”„๋กœํ† ํƒ€์ž…" ๋ฐ๋ชจ๊ฐ€ ์ž‘๋™ ์ค‘์ž…๋‹ˆ๋‹ค. ์ด์ œ ์žฌ๊ท€๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ „์—ญ ๋ณ€์ˆ˜ ์ฃผ์œ„์— ํ”„๋ก์‹œ๋ฅผ ์‚ฌ์šฉํ•œ ๋‹ค์Œ ๊ฐ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์–‡์€ ๋ž˜ํผ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ”„๋ก์‹œ๋Š” ์ด์ „ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ง€์› ๋˜์ง€ ์•Š์œผ๋ฉฐ ํด๋ฆฌํ•„ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ Jest์—์„œ ํ—ˆ์šฉ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ๋ž˜ํผ์˜ ์ผ๋ฐ˜ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

const since = (text) => {
  return new Proxy(global, {
    get: (orig, key) => {
      return (...args) => {
        try {
          const stack = orig[key](...args);
          return new Proxy(stack, {
            get: (orig, key) => {
              return (...args) => {
                try {
                  const ret = orig[key](...args);

                  // ... implement recursion here

                } catch (err) {
                  console.log('2', key, text, err);
                  throw err;
                }
              }
            }
          });
        } catch (err) {
          console.log('1', key, text, err);
          throw err;
        }
      };
    }
  });
};

์„ธ ๊ฐ€์ง€ ํ˜„์‹ค์ ์ธ ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ด ๋ฐฉ๋ฒ•์€ ํ—ˆ์šฉ๋˜๋ฏ€๋กœ ๊ธฐ๋ณธ Jest ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ •๋ฆฌํ•˜๊ณ  PR์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • Jest์— ๋Œ€ํ•ด ๋” ๊นŠ์ด ํŒŒ๊ณ ๋“ค์–ด ํ•ต์‹ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. ๋งŽ์€ ์ž‘์—…, ๊ทธ๋ž˜์„œ ์ผ๋ถ€ ํšŒ์›(๋“ค)์ด ์ด ๋ฌธ์ œ/๋ฐฉํ–ฅ์— ๋Œ€ํ•ด ๋ฐ˜๊ณต์‹์ ์œผ๋กœ ๋งํ•  ๋•Œ๊นŒ์ง€ ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ์™„๋ฃŒํ•˜๊ณ  ํŒจํ‚ค์ง€๋กœ ๊ฒŒ์‹œํ•˜์‹ญ์‹œ์˜ค. ์‰ฝ๊ฒŒ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํŽธ์ง‘: ์‹ค์ œ ์‚ฌ์šฉ:

describe('Test', () => {
  it('works', () => {
    since('It fails!').expect('a').toEqual('b');
  });
});

์‚ฌ์†Œํ•˜์ง€ ์•Š์€ ํ…Œ์ŠคํŠธ๊ฐ€ ์žˆ์„ ๋•Œ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ์ •์ƒ์œผ๋กœ ๋งŒ๋“ค๋ ค๋ฉด ๊ธฐ๋Œ€ ์ปจํ…์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ ํ…Œ์ŠคํŠธ๊ฐ€ ํ•ญ์ƒ ๊ทธ๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ง€์ • ๋งค์ฒ˜๋ฅผ ๊ธฐ์–ตํ•˜์‹ญ์‹œ์˜ค - ์ˆ˜ํ•™ ๋ณต์žก์„ฑ์„ ์ˆจ๊น๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•˜๋ฉด ์‹คํŒจ์— ๋Œ€ํ•œ ์ตœ๋Œ€ ์ •๋ณด๋ฅผ ์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๋ณต์žก์„ฑ์„ ์ˆจ๊ธฐ๋Š” ๊ฒƒ์€ ์›ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๊ธฐ๋Œ€ ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด ์ปจํ…์ŠคํŠธ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ์ƒ๊ฐ์— ์ด์ƒ์ ์ด์ง€๋Š” ์•Š์ง€๋งŒ ์ผ์ข…์˜ ์ž๋™ ์ปจํ…์ŠคํŠธ๊ฐ€ ๋” ๋‚˜์„ ๊ฒƒ์ด์ง€๋งŒ ์ง€๊ธˆ๊นŒ์ง€ ๋ณธ ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ถ€์ˆ˜๊ณ  ์‹คํŒจํ•˜๋ฉด Jest๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜๋™์œผ๋กœ ๋””๋ฒ„๊น…ํ•˜๊ฑฐ๋‚˜ ๋กœ๊น… ๋˜๋Š” _modifications._๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ…Œ์ŠคํŠธ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋œ ํŽธ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด Jasmine์—๋Š” ์‹คํŒจ์— ๋Œ€ํ•ด ๋” ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์ผ๋ถ€ ์ปจํ…์ŠคํŠธ๋ฅผ ์ธ์‡„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
Java์˜ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์ธ JUnit์—๋„ ๋˜‘๊ฐ™์€ ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ํ‹€๋ ธ๋‹ค๋ฉด ๋ฏธ์•ˆํ•˜์ง€๋งŒ ์—ฌ๊ธฐ์— ์ด โ€‹โ€‹๊ธฐ๋Šฅ์— ๋Œ€ํ•œ _๊ธฐ์ˆ ์ _ ๋ฐ˜๋ก ์ด ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  "๋ณด๊ธฐ์— ์ข‹์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€ํ•˜๋ฉด ์•ˆ ๋œ๋‹ค"์™€ ๊ฐ™์€ ๊ฒƒ์€ ๊ทธ์ € ์šฐ์Šค๊ฝ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์œ„์˜ @aaronabramov ๊ฐ€ ์ œ์•ˆํ•œ jest.debug() ์กฐ์ฐจ๋„ ์ €์—๊ฒŒ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

This:

it('has all the methods', () => {
    since('cookie is a method', () => expect(reply.cookie).toBeDefined());
});

can be supported by adding this:


// setupTestFrameworkScriptFile.js
// http://facebook.github.io/jest/docs/configuration.html#setuptestframeworkscriptfile-string
global.since = (explanation, fn) => {
    try {
        fn();
    } catch(e) {
        e.message = explanation + '\n' + e.message;
        throw e;
    }
};

๋˜ํ•œ jasmine-custom-message ๋Š” ์š”์ฒญํ•œ ๊ฒƒ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค.

describe('test', function() {
  it('should be ok', function() {
    since(function() {
      return {'tiger': 'kitty'};
    }).
    expect(3).toEqual(4); // => '{"tiger":"kitty"}'
  });
});

๋‹ค์‹œ ์—ด ๊ณ„ํš์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ตœ๊ทผ์— ์ด ๋ฌธ์ œ๊ฐ€ ์ค‘๋ณต๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•  ๋•Œ ์‚ฌ์šฉ์ž ์ง€์ • ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

ํ .. ์ด๊ฒƒ๋„ ์œ„์‹œ๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š” ๊ฒƒ. ์ด ์Šค๋ ˆ๋“œ๋ฅผ ์ฝ์€ ํ›„ Facebook์—์„œ Jest ์‚ฌ์šฉ๊ณผ ๊ด€๋ จ๋œ ์‘๋‹ต์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ณ  ์ž์‹ ์˜ ์›Œํฌํ”Œ๋กœ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ณ  ์‹ถ์ง€ ์•Š์ง€๋งŒ ๊ธฐ์กด ํ…Œ์ŠคํŠธ๋ฅผ ๋ฐฉํ•ดํ•˜์ง€ ์•Š๋Š” ๋ช‡ ๊ฐ€์ง€ ์ œ์•ˆ์ด ์žˆ์—ˆ๊ณ  ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. (์ € ํฌํ•จ) ์žˆ์Šต๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜๊ฐ€ expect() ๋˜๋Š” since() ํ˜•์‹์ด PR๋กœ ํ—ˆ์šฉ๋˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ๋‚˜๋Š” ์ด๊ฒƒ์„ ๋•๊ธฐ ์œ„ํ•ด ๊ธฐ๊บผ์ด ์‹œ๊ฐ„์„ ํ• ์• ํ•ฉ๋‹ˆ๋‹ค.

๋ฐฉ๊ธˆ ์Šค๋ ˆ๋“œ๋ฅผ ์ฝ๊ณ  ์–‘์ชฝ์—์„œ ์ข‹์€ ์ฃผ์žฅ์„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค. @timoxley๊ฐ€ ์›๋ž˜ ๊ฒŒ์‹œํ•œ ๊ฒƒ๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ ์‚ฌ์šฉ์ž ์ง€์ • ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ํ™•์‹คํžˆ ์›ํ•ฉ๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

import assert from 'assert'
import chalk from 'chalk'

test('api works', () => {
  assert.deepEqual(
    api(),
    [],
    chalk.red('api without magic provides no items')
  )
  assert.deepEqual(
    api(0),
    [],
    chalk.red('api with zero magic also provides no items')
  )
  assert.deepEqual(
    api(true),
    [1, 2, 3],
    chalk.red('api with magic enabled provides all items')
  )
})

์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ๋งค์šฐ ์ž˜ ์ž‘๋™ํ•˜์ง€๋งŒ ๋ถ„ํ•„์„ ์‚ฌ์šฉํ•˜์—ฌ ๋นจ๊ฐ„์ƒ‰์„ ์–ป๋Š” ๊ฒƒ์„ ํ”ผํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค expect

๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ •์งํ•˜๊ฒŒ ๊ตฌํ˜„๋˜์—ˆ๋Š”์ง€์— ๋Œ€ํ•ด ๋ณ„๋กœ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์ด ์„ ํ˜ธํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•˜์—ฌ since ์— ๋Œ€ํ•œ ๋Œ€์•ˆ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

const expectWithMessage = expect.withMessage(
  'api with magic enabled provides all items'
)
expectWithMessage(api(true)).toEqual([1, 2, 3])

// could be rewritten like
expect
  .withMessage('api with magic enabled provides all items')(api(true))
  .toEqual([1, 2, 3])

since ๋ณด๋‹ค ๋” ์ข‹์•„ํ•˜๋Š”์ง€ ํ™•์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ญ๋“ ์ง€ ๋‹ค ์ž˜์–ด์šธ๋ ค์š” ์ •๋ง ๊ฐ–๊ณ ์‹ถ๋„ค์š” :)

์•„, ๊ทธ๋ฆฌ๊ณ  ๋Œ“๊ธ€์— ๋‹ตํ•˜์ž๋ฉด:

์ด๊ฒƒ์ด ๋ณ„๋กœ ์œ ์šฉํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ์ด์œ ๋Š” ์—”์ง€๋‹ˆ์–ด๊ฐ€ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์— ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ณ  ์‹ถ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋“ค์„ ๋” ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๊ฐ€ ํ•˜๋Š” ๋ชจ๋“  ์ผ์€ ๋” ๋‚˜์œ ํ…Œ์ŠคํŠธ๋กœ ์ด์–ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์„ ๋” ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ถ”๊ฐ€ ๋ณ€๊ฒฝ์ด ๋˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ…Œ์ŠคํŠธ๋ฅผ ๋””๋ฒ„๊ทธํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“œ๋Š” "์‹œ๊ฐ„ ๋‚ญ๋น„"๋ฅผ ์›ํ•˜์ง€ ์•Š๋Š” ์‚ฌ๋žŒ๋“ค์€ ์œ ์šฉํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ๊ฑด๋„ˆ๋›ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‹œ๊ฐ„์„ ๋‚ด์–ด ์ฃผ์žฅ์„ ์กฐ๊ธˆ ์„ค๋ช…ํ•ด์ฃผ์‹  ์—”์ง€๋‹ˆ์–ด :wink:

์•ˆ๋…•ํ•˜์„ธ์š” @cpojer ์ด์— ๋Œ€ํ•œ ์—…๋ฐ์ดํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

Jest๋Š” ์ด ๋ฌธ์ œ๋ฅผ ์ œ์™ธํ•˜๊ณ ๋Š” ํ›Œ๋ฅญํ•˜๊ฒŒ ์ž‘๋™ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค... ํ˜„์žฌ ์ €๋Š” for ๋ฃจํ”„ ๋‚ด์—์„œ ์‹คํŒจํ•œ ์–ด์„ค์…˜์„ ์ˆ˜์ •ํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ๊ตฐ๋ถ„ํˆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
expectationsArray.forEach(expectation => expect(...))

์‚ฌ์šฉ์ž ์ •์˜ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€ ์—†์ด ์–ด๋–ค ๊ธฐ๋Œ€๊ฐ€ ์‹คํŒจํ•˜๋Š”์ง€ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค(๋‚ด๊ฐ€ ์ž˜๋ชปํ•˜์ง€ ์•Š๋Š” ํ•œ..?)

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

@mj-airwallex ์˜ˆ๋ฅผ ๋“ค์–ด for ๋ฃจํ”„์—์„œ test ๋กœ ๊ธฐ๋Œ€์น˜๋ฅผ ๊ฐ์Œ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const expectationsArray = [[0, 'a'], [1, 'b']];

expectationsArray.forEach(([expectation, desc]) => {
  test(`test ${desc}`, () => {
    expect(expectation).toBeGreaterThanOrEqual(2);
  });
});

๋˜ํ•œ ๊ธฐ๋Œ€ํ•˜๋Š” ๋™์•ˆ ์‚ฌ์šฉ์ž ์ง€์ • ๋ฉ”์‹œ์ง€๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋†๋‹ด์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. test ์•„๋ž˜์— ๊ธฐ๋Œ€์น˜๋ฅผ ๋ž˜ํ•‘ํ•˜๋Š” ๊ฒƒ์€ ๋น„๋™๊ธฐ์‹ ํ˜ธ์ถœ์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์— ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Jest๋Š” ํ”„๋ผ๋ฏธ์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” describe (#2235 )๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ test ๋กœ ๋ž˜ํ•‘ํ•˜๋Š” ๊ฒƒ๊ณผ ํ•จ๊ป˜ ๋น„๋™๊ธฐ ํ˜ธ์ถœ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์—ฌ๋Ÿฌ test ์ค‘์ฒฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ์˜ˆ์ž…๋‹ˆ๋‹ค.

async function getArray() {
  return [0,0,0,0,0,0]
}

describe('Custom messages with async', async () => {
  const array = await getArray();
  array.forEach((item) => {
    test(`test${item}`, () => {
      expect(item).toBe(0)
    });
  });
})

์ด๊ฒƒ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

OP์˜ ๋ฌธ์ œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด("์–ด๋–ค ๊ธฐ๋Œ€๊ฐ€ ์‹คํŒจํ–ˆ๋Š”์ง€ ์ฆ‰์‹œ ๋ช…ํ™•ํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค"), ์ด์ œ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Jest 22๋ถ€ํ„ฐ ์šฐ๋ฆฌ๋Š” ์‹คํŒจํ•œ ์ฃผ์žฅ์˜ ์ปจํ…์ŠคํŠธ๋ฅผ ์ธ์‡„ํ•ฉ๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ๋ฉ”์‹œ์ง€๊ฐ€ ์—ฌ์ „ํžˆ ํ•„์š”ํ•ฉ๋‹ˆ๊นŒ? _is_์ธ ๊ฒฝ์šฐ ์–ด์„ค์…˜ ์œ„ ๋˜๋Š” ์˜†์— ์žˆ๋Š” ์ฝ”๋“œ ์ฃผ์„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

image

๋น„๋™๊ธฐ ์„ค๋ช…์€ ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค(์ถ”๊ฐ€๋œ ์ฝ”๋“œ ํ”„๋ ˆ์ž„์œผ๋กœ๋Š” ๋„์›€์ด ๋˜์ง€ ์•Š์Œ).

๋น„๋™๊ธฐ ์„ค๋ช…์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๋Œ€์‹  beforeEach ๋˜๋Š” beforeAll ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

@kentcdodds beforeEach ๋˜๋Š” beforeAll ๋กœ ์ด๊ฒƒ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์˜ ์˜ˆ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? beforeEach ๋ฐ beforeAll ์— ํ•„์š”ํ•œ ๋ชจ๋“  ๋น„๋™๊ธฐ ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋ฅผ ๋นŒ๋“œํ•˜๋ ค๊ณ  ํ•˜๋ฉด ๊ฒฐ๊ตญ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ์ค‘์ฒฉ๋œ test ๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์•„, ๋‹น์‹ ์ด ๊ทธ ๋น„๋™๊ธฐ ํ†ตํ™”๋กœ ๋ฌด์—‡์„ ํ•˜๊ณ  ์žˆ์—ˆ๋Š”์ง€ ๋ณด๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค ๐Ÿ˜‚ ๋„ค, beforeEach ๋˜๋Š” beforeAll ์„(๋ฅผ) ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@SimenB , ์ปจํ…์ŠคํŠธ๋ฅผ ์ธ์‡„ํ•˜๋ฉด ์ด๋ฏธ ๋งŽ์€ ๋„์›€์ด ๋˜๋ฉฐ ์‚ฌ์šฉ์ž ์ง€์ • ๋ฉ”์‹œ์ง€์™€ ๊ด€๋ จ๋œ ๋Œ€๋ถ€๋ถ„์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๊ทธ๋Ÿฌ๋‚˜ ๋ฃจํ”„ ๋‚ด์—์„œ ์˜ˆ์ƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ๋„์›€์ด ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž ์ง€์ • ๋ฉ”์‹œ์ง€๋ฅผ ์ธ์ˆ˜๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@tojuhaka ์ด๊ฒƒ์„ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค : https://github.com/negativetwelve/jest-plugins/tree/master/packages/jest-plugin-context

OP์˜ ๋ฌธ์ œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด("์–ด๋–ค ๊ธฐ๋Œ€๊ฐ€ ์‹คํŒจํ–ˆ๋Š”์ง€ ์ฆ‰์‹œ ๋ช…ํ™•ํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค"), ์ด์ œ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ, ๋Œ€๋ถ€๋ถ„์˜ Jest ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ–๊ฒŒ ๋˜๋Š” ๋ณ€ํ™˜ ์ „์— ์›๋ณธ ์†Œ์Šค์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ ์›๋ณธ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. IMO๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์‹คํŒจ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ์ž๊ฐ€ ์ œ๊ณตํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ์ธ์‡„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•˜๋Š” ๊ฒƒ์— ๋น„ํ•ด ์•ฝ๊ฐ„ ๋ฌด๊ฒ์ง€๋งŒ ์ถฉ๋ถ„ํžˆ ์ข‹์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Jest๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๋Š”๋ฐ ์ด์™€ ๊ฐ™์€ ๊ธฐ๋Šฅ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋‚ด ์‚ฌ์šฉ ์‚ฌ๋ก€:
๊ฐ์ฒด์˜ ์†์„ฑ์ด ์ง„์‹ค์ด๋ผ๊ณ  ์ฃผ์žฅํ•˜๋Š” ํ…Œ์ŠคํŠธ๋Š” ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. ์–ด์„ค์…˜์ด ์‹คํŒจํ•  ๊ฒฝ์šฐ ๊ฐœ์ฒด๋ฅผ ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์‹คํŒจ๋ฅผ ๋” ๋นจ๋ฆฌ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด toHaveProperty ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

test('property', () => {
  expect({foo: 'bar'}).toHaveProperty('baz', 'foobar');
});

image

๊ฑฐ๊ธฐ์— ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜๋ฅผ ์‚ญ์ œํ•˜์‹ญ์‹œ์˜ค. _some_ ๊ฐ’์ด ์žˆ๋‹ค๊ณ  ์ฃผ์žฅํ•˜๋ ค๋Š” ๊ฒฝ์šฐ expect.anything() ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
toMatchObject ๋Š” ๋˜ ๋‹ค๋ฅธ ๋Œ€์•ˆ์ž…๋‹ˆ๋‹ค.

์›ํ•˜๋Š” ๊ฒฝ์šฐ assert ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

test('property', () => {
  const obj = {foo: 'bar'};
  assert.equal(obj.baz, 'foobar', JSON.stringify(obj));
});

image

ํŒ ๊ณ ๋งˆ์›Œ. assert.equal(obj.baz, 'foobar', JSON.stringify(obj)); ๋Š” ๋‚ด ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ์— ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

@SimenB @mpseidel ์ฃผ์žฅ์ด๋ž€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ํƒ€์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๊นŒ? jest ๋ฌธ์„œ์—์„œ ์•„๋ฌด๊ฒƒ๋„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@sharikovvladislav assert ๋Š” ๋…ธ๋“œ ์ฝ”์–ด ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค https://nodejs.org/api/assert.html

@mpseidel ์•— ! ๋‚˜๋Š” ๋ชฐ๋ž๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํšจ๊ณผ๊ฐ€์žˆ๋‹ค.

๋‹ค์Œ ์ฝ”๋“œ ์กฐ๊ฐ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ด๋Ÿฌํ•œ ์ œํ•œ์„ ํ•ด๊ฒฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(TypeScript์—์„œ JS์— ๋Œ€ํ•œ ์œ ํ˜• ์ฃผ์„์„ ์ œ๊ฑฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค).
export const explain = (expectation: () => void, explanation: string) => { try { expectation(); } catch(e) { console.log(explanation) throw e; } }

์•ˆ๋…•,
์•„๋ฌด๋„ ๋ฃจํ”„์— ๋Œ€ํ•ด ์–ธ๊ธ‰ํ•˜์ง€ ์•Š์•˜๋‹ค๋Š” ์‚ฌ์‹ค์— ๋†€๋ž์Šต๋‹ˆ๋‹ค. ๋ฉ”์‹œ์ง€๋Š” ๋‹จ์ˆœํ•œ ๋ฌธ์ž์—ด์ด ์•„๋‹ˆ๋ผ ๋ฃจํ”„ ๋ฐ˜๋ณต์— ๋”ฐ๋ฅธ ๋™์  ๋ฌธ์ž์—ด์ž…๋‹ˆ๋‹ค.
jest-plugin-context ๋Š” ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค. ๋•๋ถ„์— ์ž‘๋™ํ•˜์ง€๋งŒ ์•ฝ๊ฐ„ ๋ฌด๊ฒ๊ณ  ์ดˆ๊ธฐ ๋ฌธ์ œ๋Š” ์—ฌ์ „ํžˆ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ํ…Œ์ŠคํŠธ๋ฅผ ๋ด

describe('MyStuff', () => {
    it('should render and contain relevant inputs', () => {
      const wrapper = shallowWrapped(<MyStuff />);
      const expectedKeys = ['love','jest','but','need','details','for','expect'];
      expectedKeys.forEach((key) => {
        expect(wrapper.find({ id: key }).length).toEqual(1);
      });
    });
  });

๋‹น์‹ ์˜ ๋ฒ”์ธ์„ ์ฐพ๋Š” ํ–‰์šด์„ ๋น•๋‹ˆ๋‹ค. ์ง€๊ธˆ ๋‹น์žฅ {len:.., key:..} ์™€ ๊ฐ™์€ ๊ฐœ์ฒด๋ฅผ ๋Œ€์‹  ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ํ…Œ์ŠคํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊นจ๋—ํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉ์ž ์นœํ™”์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
์ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์˜ˆ๋ฅผ ๋“ค์–ด ์–‘์‹ ๋ฐ ํ•ญ๋ชฉ ๋ Œ๋”๋ง ํ™•์ธ๊ณผ ๊ด€๋ จ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
๊ตฌ๋ฌธ์€ toEqual(1).context("my message") ๋˜๋Š” toEqual(1, "my message") ๋งŒํผ ๊ฐ„๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋ฌผ๋ก  ๊ตฌํ˜„์ด ํ•ญ์ƒ ๋” ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์œผ๋ฉฐ Jest์—์„œ ์ˆ˜ํ–‰ํ•œ ํ›Œ๋ฅญํ•œ ์ž‘์—…์„ ์กด๊ฒฝํ•ฉ๋‹ˆ๋‹ค).

chai ์™€ ๊ฐ™์€ ํ˜•์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ๋ฉ”์‹œ์ง€๋ฅผ ์˜ˆ์ƒ ํ˜ธ์ถœ์— ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

expect(foo, 'this detail').toEqual(2)

ํ‹ฐ

์ด์ „์— ์žฌ์Šค๋ฏผ์„ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ง€์›๋˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ์ฐพ์•„ ์—ฌ๊ธฐ์— ์™”์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ afik ์ด๋Ÿฌํ•œ ๊ฒƒ๋“ค์€ ๋ชจ๋‘ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•˜๋ฉด ์•ˆ ๋ ๊นŒ์š”?

describe('MyStuff', () => {
    describe('should render and contain relevant inputs', () => {
      const wrapper = shallowWrapped(<MyStuff />);
      const expectedKeys = ['love','jest','but','need','details','for','expect'];

      expectedKeys.forEach((key) => {
        it(`contains key "${key}"`, () =>
          expect(wrapper.find({ id: key }).length).toEqual(1)
        )
      })
  });
});

2018-04-18-222246_646x390_scrot

@akkerman ์ข‹์€ ์†”๋ฃจ์…˜์ž…๋‹ˆ๋‹ค. describe ๋ฐ it์€ jest์—์„œ ์ œ๊ณตํ•˜๋Š” ๋งˆ๋ฒ•์˜ ์ „์—ญ์ด๋ฏ€๋กœ ๋ชจํ˜ธํ•˜๊ฒŒ ๋Š๊ปด์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์ธ์ •ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฃจํ”„์—์„œ 't'๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์‹ ํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์ˆ˜์ •์ž๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

expect(foo).toEqual(bar).because('reason with %s placeholders')

๋˜๋Š” ์•„๋งˆ๋„ ๊ธฐ๋Šฅ

expect(foo).toEqual(bar).explainedBy((result) => `Lorem ipsum ${result}`)

๋‹ค๋ฅธ ์ˆ˜์‹์–ด๋Š” ๋นจ๋ฆฌ ์ฝ์„ ์ˆ˜ ์—†๊ฒŒ ๋˜๋Š” ๊ฒƒ ๊ฐ™์•„์š”.
ํ‹ฐ

2018-04-19 13:47 GMT+02:00 ฮป โ€ข Geovani de Souza [email protected] :

๋‹ค๋ฅธ ์ˆ˜์ •์ž๋ฅผ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

expect(foo).toEqual(bar).because('%s ์ž๋ฆฌ ํ‘œ์‹œ์ž๊ฐ€ ์žˆ๋Š” ์ด์œ ')

๋˜๋Š” ์•„๋งˆ๋„ ๊ธฐ๋Šฅ

๊ธฐ๋Œ€(foo).toEqual(bar).explainedBy((๊ฒฐ๊ณผ) => Lorem ipsum ${result} )

โ€”
๋‹น์‹ ์ด ๋Œ“๊ธ€์„ ๋‹ฌ์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/facebook/jest/issues/1965#issuecomment-382705387 ๋˜๋Š” ์Œ์†Œ๊ฑฐ
์Šค๋ ˆ๋“œ
https://github.com/notifications/unsubscribe-auth/AAM5PwBCvET1KdEDeDEF7gGo708Naj8oks5tqHlSgaJpZM4Kc6Uu
.

--


ํƒ€๋ฅด์ œ์ด ํ›„์„ธ
๋ชจ๋นŒ: 920 63 413

expect ์ž‘๋™ ๋ฐฉ์‹์€ ๋˜์ง€๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ์–ด์จŒ๋“  ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

expect(something, 'some helpful text on failure').toEqual(somethingElse) ๋˜๋Š” expect.context(something, 'some helpful text on).toEqual(somethingElse) ๊ฐ€ ๊ฐ€์žฅ ์ข‹์€ ๋Œ€์•ˆ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ๋‘˜ ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ๋งˆ์Œ์— ๋“ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด๊ฑฐ ์žฌ๊ฐœ๋ด‰ ๊ฐ€๋Šฅํ•œ๊ฐ€์š”? Jest๋Š” ์—ฌ์ „ํžˆ ์—ฌ๋Ÿฌ ์ƒํ˜ธ ์ž‘์šฉ์—์„œ ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝ๋˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•œ ์ข‹์€ ์†”๋ฃจ์…˜์ด ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์ผ๋ จ์˜ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ์ƒํƒœ ์ €์žฅ React ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝ๋˜๋Š”์ง€ ํ…Œ์ŠคํŠธ
  • Puppeteer๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ์ƒํ˜ธ ์ž‘์šฉ์—์„œ ์›น ํŽ˜์ด์ง€๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝ๋˜๋Š”์ง€ ํ…Œ์ŠคํŠธ

์ด ๋‘ ๊ฒฝ์šฐ ๋ชจ๋‘ ์ผ๋ จ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ๊ฐ ์ž‘์—… ํ›„์— ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€(๋˜๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋Š”์ง€) ์ฃผ์žฅํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋‹ค์ค‘ ์ฃผ์žฅ ํ…Œ์ŠคํŠธ๊ฐ€ ๋•Œ๋•Œ๋กœ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. beforeEach ๋กœ ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ด ํ•ญ์ƒ ๊ฐ€๋Šฅํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

์ €๋Š” ์ด๊ฒƒ์ด ์ •๋ง ์œ ์šฉํ•  ์ƒํ™ฉ์„ ๊ณ„์† ์ฐพ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ @callumlock์ด ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ ์ƒํ˜ธ ์ž‘์šฉ ๋ฐ ์–ด์„ค์…˜์„ ์‹คํ–‰ํ•  ๋•Œ.

์‚ฌ๋žŒ๋“ค์ด ์‹ซ์–ดํ•˜์ง€ ์•Š๋Š” API๋ฅผ ์ƒ๊ฐํ•ด ๋‚ธ๋‹ค๋ฉด ์ด๊ฒƒ์ด ๋‹น์‹ ์ด ์ถ”๊ตฌํ•  ์˜ํ–ฅ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ •๋ง ์œ ์šฉํ•˜๊ณ  ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ๊ธฐ๋Šฅ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์ œ์•ˆ๋œ ์†”๋ฃจ์…˜์„ ์š”์•ฝํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

expect(api()).toEqual([]) // api without magic provides no items
it('api without magic provides no items', () => expect(api()).toEqual([]))
test('api without magic provides no items', () => expect(api()).toEqual([]))
expect(api()).toHaveNoItems()

expect(api(), 'api without magic provides no items').toEqual([])
expect(api()).because('api without magic provides no items').toEqual([])
since('api without magic provides no items').expect(api()).toEqual([]))
because('api without magic provides no items').expect(api()).toEqual([]))
jest.debug('api without magic provides no items'); expect(api()).toEqual([]))

.because() ํ›„ํ–‰์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ ์˜ต์…˜์œผ๋กœ ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ฒซ ๋ฒˆ์งธ ๊ทธ๋ฃน์˜ ๋„ค ๊ฐ€์ง€ ์˜ต์…˜์ด ๋ชจ๋‘ ์˜ค๋Š˜ ์ง€์›๋ฉ๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ์ฒซ ๋ฒˆ์งธ ์˜ต์…˜(์ฃผ์„์ด ์žˆ๋Š” ์ฝ”๋“œ ํ”„๋ ˆ์ž„)์ด ํ›Œ๋ฅญํ•˜๊ฒŒ ์ž‘๋™ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. ์ปค์Šคํ…€ ๋งค์ฒ˜(์˜ต์…˜ 4)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ์ข‹์Šต๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•œ ์›€์ง์ž„์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๊ฐ€ ์ดํ•ดํ•ด์•ผ ํ•  ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๊ทธ๋ฃน์˜ ์˜ต์…˜๋ณด๋‹ค ๋‘ ๋ฒˆ์งธ ๊ทธ๋ฃน์˜ ์˜ต์…˜์— ๋Œ€ํ•ด ๋” ๋งค๋ ฅ์ ์ธ ์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋‘ ๋ฒˆ์งธ ๊ทธ๋ฃน์€ ์šฐ๋ฆฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“  ๋งค์ฒ˜(๋น„๋™๊ธฐ ๋งค์ฒ˜, ๋น„๋Œ€์นญ ๋งค์ฒ˜, ์ŠคํŒŒ์ด ๋งค์ฒ˜, throw ๋งค์ฒ˜, ์•ฝ์† ๋งค์ฒ˜ ๋ฐ ์‚ฌ์šฉ์ž ์ง€์ • ๋งค์ฒ˜)์— ๋Œ€ํ•œ ํ•ต์‹ฌ ์œ ์ง€ ๊ด€๋ฆฌ๋ฅผ ์ •๋‹นํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌด์—‡์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๊นŒ?

์•ˆ๋…•,
๊ธฐ๋ณธ์ ์œผ๋กœ ๋ช‡ ๊ฐ€์ง€ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋‹ค์ค‘ ์ฃผ์žฅ ํ…Œ์ŠคํŠธ(ํ…Œ์ŠคํŠธ์—์„œ ์—ฌ๋Ÿฌ ํ•ญ๋ชฉ์„ ์ฃผ์žฅํ•ด์•ผ ํ•จ)
  • ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ ์–ด์„ค์…˜ ์ปจํ…์ŠคํŠธ(์˜ˆ: ๋งŽ์€ ํ…Œ์ŠคํŠธ๋ฅผ ๋ฐ›์•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹คํŒจํ•œ ๊ฐœ์ฒด์˜ ํŠน์ • ํ•„๋“œ๋ฅผ ์ธ์‡„ํ•˜๊ธฐ ์œ„ํ•ด ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์˜ ๋ณ€์ˆ˜๋ฅผ ๋” ๋ช…ํ™•ํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ๋ฅผ ์›ํ•จ)
  • ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ ์–ด์„ค์…˜(์–ด์„ค์…˜์„ ์ƒ์„ฑํ•˜๋Š” ๋ฃจํ”„๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค)

์ฒซ ๋ฒˆ์งธ ๊ทธ๋ฃน ์˜ต์…˜์€ ์ฃผ๋กœ ์ฒซ ๋ฒˆ์งธ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ œ์•ˆ๋œ ๋Œ€๋กœ ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ ์–ด์„ค์…˜์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํ…Œ์ŠคํŠธ๊ฐ€ ๋ฃจํ”„์—์„œ ์ƒˆ ํ…Œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก it ๋ฐ test ์— ๋Œ€ํ•œ ํ˜ธ์ถœ์„ ์ค‘์ฒฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ์ฃผ์žฅ ์ด ์•„๋‹ˆ๋ผ ํ…Œ์ŠคํŠธ ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. 1000๊ฐœ ์š”์†Œ ๋ฐฐ์—ด์˜ ๊ฐ ์š”์†Œ์— ๋Œ€ํ•ด ๋ฌด์–ธ๊ฐ€๋ฅผ ์ฃผ์žฅํ•˜๊ณ  ์‹ถ๋‹ค๊ณ  ์ƒ์ƒํ•ด ๋ณด์‹ญ์‹œ์˜ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ…Œ์ŠคํŠธ ์š”์•ฝ์ด ๋ถ€ํ’€๋ ค์ง‘๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋™์  ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์—ฌ์ „ํžˆ ๋“œ๋ฌผ๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ง€ ๊ด€๋ฆฌ์ž์—๊ฒŒ ์ตœ์†Œํ•œ์˜ ์ž‘์—…์ด ํ•„์š”ํ•œ ์†”๋ฃจ์…˜์„ ๊ณ ์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ because/since ์†”๋ฃจ์…˜์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค. ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋“ค๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ตฌํ˜„์€ ๋Œ€๋ถ€๋ถ„ expect ๋ฅผ try/catch ์— ๋ž˜ํ•‘ํ•˜์—ฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ธ์‡„ํ•˜๊ณ  ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
jest.debug ์ด์ƒํ•˜๊ฒŒ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ๊ฐ€ ์‹ค์ œ๋กœ ํ†ต๊ณผํ•˜๋”๋ผ๋„ ๋””๋ฒ„๊น…์ด ๋ฉ”์‹œ์ง€๋ฅผ ์ธ์‡„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
"๋งˆ์ง€๋ง‰ ์ธ์ˆ˜" ์˜ต์…˜๋„ ์ข‹์ง€๋งŒ expect ๊ฐ€ ๋‹ค์–‘ํ•œ ์ธ์ˆ˜๋ฅผ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์–ด๋–ค ์˜ต์…˜๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹จ์ง€ ๊ทธ ๊ธฐ๋Šฅ์„ ์›ํ•œ๋‹ค. ์ €๋Š” jest.debug API์— ๋Œ€ํ•ด ๋ณ„๋กœ ๊ด€์‹ฌ์ด ์—†์ง€๋งŒ ์ด ๊ธฐ๋Šฅ์„ ์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜๋ฏธ๊ฐ€ ์žˆ๋Š” ์œ ์ผํ•œ API๋ผ๋ฉด ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

@kentcdodds ๊ธฐ์กด ์˜ต์…˜ 4๊ฐœ๋Š” ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

@eric-burel test.each ๋ฐ describe.each ๊ฐ€ Jest 23์— ์ถ”๊ฐ€๋œ ๊ฒƒ์„ ๋ณด์•˜์Šต๋‹ˆ๊นŒ(Jest <23์˜ ๊ฒฝ์šฐ ๋…๋ฆฝ ์‹คํ–‰ํ˜•์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)?

๋‚ด๊ฐ€ ๋งํ–ˆ๋“ฏ์ด, ๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ์–ด๋–ค ์˜ต์…˜์„ ์„ ํƒํ•˜๋Š”์ง€ ๋ณ„๋กœ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ์ด ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž„ ๋ฟ์ž…๋‹ˆ๋‹ค. ์šฐ์„  ์ˆœ์œ„๋ฅผ ์ง€์ •ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  1. expect(api(), 'api without magic provides no items').toEqual([])
  2. because('api without magic provides no items').expect(api()).toEqual([]))
  3. since('api without magic provides no items').expect(api()).toEqual([]))
  4. expect(api()).because('api without magic provides no items').toEqual([])
  5. jest.debug('api without magic provides no items'); expect(api()).toEqual([]))

(test|describe).each ๋Š” ํ›Œ๋ฅญํ•˜์ง€๋งŒ ๋‹จ์ผ ํ…Œ์ŠคํŠธ์—์„œ ์—ฌ๋Ÿฌ ์ž‘์—…/์–ด์„ค์…˜์„ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์€ ํ˜„์žฌ 4๊ฐ€์ง€ ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

expect(api()).toEqual([]) // api without magic provides no items
it('api without magic provides no items', () => expect(api()).toEqual([]))
test('api without magic provides no items', () => expect(api()).toEqual([]))
expect(api()).toHaveNoItems()

์ด๊ฒƒ๋“ค์ด ๋ญ๊ฐ€ ์ž˜๋ชป๋๋‚˜์š”? ์ œ์•ˆ๋œ _new_ ์†”๋ฃจ์…˜์€ ์ด๋Ÿฌํ•œ ๊ธฐ์กด ์†”๋ฃจ์…˜๋ณด๋‹ค ์•ฝ๊ฐ„ ๋” ๋‚˜์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์œ ์ง€ ๊ด€๋ฆฌ ๋น„์šฉ์„ ์ •๋‹นํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ์ด์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@rickhanlonii ๋‹ˆ์Šค test.each ์— ๋Œ€ํ•ด ๋ชฐ๋ž์Šต๋‹ˆ๋‹ค. ์ •๋ง ์ข‹์€ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ง€์ ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋ฐฐ์—ด์—์„œ ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ ํ…Œ์ŠคํŠธ์ธ ๋‚ด ์„ธ ๋ฒˆ์งธ ์‚ฌ์šฉ ์‚ฌ๋ก€์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๊ทธ๊ฒƒ์€ ๋‚ด๊ฐ€ ๋‚˜์—ดํ•œ ๋‘ ๋ฒˆ์งธ ํ•ญ๋ชฉ์„ ๋‚จ๊ฒผ์Šต๋‹ˆ๋‹ค: ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ์‹คํŒจ ๋ฉ”์‹œ์ง€๊ฐ€ ์žˆ์–ด์„œ ๋””๋ฒ„๊น…์ด ๋” ๋นจ๋ผ์กŒ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ๋งŽ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ๊ฐœ์ฒด ํ•„๋“œ ๊ฐ’์„ ํ…Œ์ŠคํŠธํ•  ๋•Œ ์‹คํŒจ ์‹œ ์ „์ฒด ๊ฐœ์ฒด๋ฅผ ์ธ์‡„ํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฏธ๋ฏธํ•˜๊ฑฐ๋‚˜ ์•ฝ๊ฐ„ ์ค‘๋ณต๋˜๋”๋ผ๋„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์„ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ํ•ฉ๋ฒ•์ ์ธ imo์ž…๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ์šฐ๋ฆฌ๋Š” it ๋ฐ test ๋‘˜ ๋‹ค ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฐจ์ด์ ์ด ์—†๋Š” ํ•œ ์ด๊ฒƒ์€ ๋Œ€๋ถ€๋ถ„ ํŽธ์•ˆํ•จ์„ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋ฏธ๋ฏธํ•˜์ง€๋งŒ ์ด ์Šค๋ ˆ๋“œ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด ์‚ฌ์šฉ์ž๊ฐ€ ์‹ค์ œ๋กœ ๊ธฐ๋Œ€ํ•˜๋Š” ๊ฒƒ(๋ง์žฅ๋‚œ ์—†์Œ)์ž…๋‹ˆ๋‹ค.

ํŽธ์ง‘: it ๋˜๋Š” test ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ์—์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•ด ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ ์ด๋ฆ„์€ ์œ ํšจํ•œ ์†”๋ฃจ์…˜์ด์ง€๋งŒ ์–ด์„ค์…˜ ์ƒ์„ฑ์„ ์˜๋ฏธํ•  ๋•Œ ํ…Œ์ŠคํŠธ ์ƒ์„ฑ์„ ์ •๋ง ์ข‹์•„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. . ์ด ์Šค๋ ˆ๋“œ์—์„œ ์†”๋ฃจ์…˜์ด ์ œ๊ณต๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€ ์•Š์•˜์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฑด ๋ฏธ์ณค์–ด. expect()์— ๋‘ ๋ฒˆ์งธ ์„ ํƒ์  ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ์€ (์„ ํƒ์ ์œผ๋กœ), ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์‚ฌ๋žŒ์€ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Mocha๋Š” ์ด๊ฒƒ์„ ์˜์›ํžˆ ํ•ด์™”์Šต๋‹ˆ๋‹ค... ๊ทธ๊ฒƒ์€ ์ œ๊ฐ€ ๋ช‡ ๋…„ ์ „์— Jasmine์„ ํฌ๊ธฐํ•œ ์ด์œ  ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์žฌ์Šค๋ฏผ ํŒŒ์ƒ๋ฌผ.

์˜ค๋ฅ˜ ์‹œ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ์€ ๋‹ค๋ฅธ ๋งŽ์€ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๊ด€๋ก€์ด๋ฉฐ Jest์—์„œ๋Š” ์ด๋ฅผ ๋ณผ ์ˆ˜ ์—†๋‹ค๋Š” ์‚ฌ์‹ค์— ๋†€๋ž์Šต๋‹ˆ๋‹ค. ์ด ์Šค๋ ˆ๋“œ์—์„œ ๋งŽ์€ ์œ ์šฉํ•œ ์˜ˆ์ œ๋ฅผ ์ฐพ์•˜์ง€๋งŒ(๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค) ํ…Œ์ŠคํŠธ ์‹คํŒจ ์‹œ ์‚ฌ์šฉ์ž ์ง€์ • ์˜ค๋ฅ˜๋ฅผ ์ธ์‡„ํ•˜๋Š” ๋ช…์‹œ์ ์ธ ๋ฐฉ๋ฒ•์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ Jest์˜ ์œ ์šฉ์„ฑ์— ์ข‹์€ ์ถ”๊ฐ€ ์‚ฌํ•ญ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ(JS๊ฐ€ ์•„๋‹Œ ํ”„๋ ˆ์ž„์›Œํฌ ํฌํ•จ)์— ์ต์ˆ™ํ•œ ๊ฐœ๋ฐœ์ž๊ฐ€ Jest๋ฅผ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@mattphillips ์‚ฌ์šฉ์ž ์˜์—ญ์— ์†”๋ฃจ์…˜์ด ์กด์žฌํ•˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๊ธฐ์—์„œ jest-chain๊ณผ ์œ ์‚ฌํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ? ์˜ˆ: expect ์— ๋Œ€ํ•œ ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜

์†”์งํžˆ ์ด๊ฒƒ์€ ๋Œ€๋ถ€๋ถ„์˜ JS ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๋งค์šฐ ํ‘œ์ค€์ ์ธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ •์˜ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋กœ ๋ชจ๋“  ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ Jest์—์„œ ์ฐพ์ง€ ๋ชปํ•œ ๊ฒƒ์— ๋งค์šฐ ์‹ค๋งํ–ˆ์Šต๋‹ˆ๋‹ค.

@SimenB ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค ์˜ค๋Š˜ ์•„์นจ์—์„œ์•ผ ๊ท€ํ•˜์˜ ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค!

์˜ˆ, ์ด๊ฒƒ์€ userland์—์„œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐฉ๊ธˆ jest-expect-message ๋กœ ์ถœ์‹œํ–ˆ์Šต๋‹ˆ๋‹ค. https://github.com/mattphillips/jest-expect-message

ํ”ผ๋“œ๋ฐฑ ํ™˜์˜:๋ฏธ์†Œ:

๊ต‰์žฅํ•ฉ๋‹ˆ๋‹ค, ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

@cpojer

์ด๊ฒƒ์ด ๋ณ„๋กœ ์œ ์šฉํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ์ด์œ ๋Š” ์—”์ง€๋‹ˆ์–ด๊ฐ€ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ์— ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ณ  ์‹ถ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋“ค์„ ๋” ์–ด๋ ต๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ๊ฐ€ ํ•˜๋Š” ๋ชจ๋“  ์ผ์€ ๋” ๋‚˜์œ ํ…Œ์ŠคํŠธ๋กœ ์ด์–ด์งˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋‘๊ฐ€์ง€:

  1. ๊ธฐ๋Œ€()์— ์„ ํƒ์  ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๊ฑฐ์˜ ์–ด๋ ค์šด ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค.
  2. ๊ฐœ๋ฐœ์ž๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•˜๊ณ  ์‹ถ์€ ์ผ์€ ํ…Œ์ŠคํŠธ ์‹คํŒจ์˜ ์›์ธ์„ ๋””๋ฒ„๊น…ํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ข…์ข… ์˜ˆ์ƒ ๋Œ€ ์ˆ˜์‹ ์€ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด์ง€๋งŒ ์‹คํŒจ ์›์ธ์— ๋Œ€ํ•œ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

Jest์— ์˜ค๊ธฐ ์ „์— Mocha/Chai์™€ ํ…Œ์ดํ”„๋ฅผ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ ์ด๊ฒƒ์€ ์ •๋ง ๊ฑฐ๋ž˜ ์ฐจ๋‹จ๊ธฐ์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ง€์ • ๋ฉ”์‹œ์ง€ ์ง€์›์„ ๊ธฐ๋Œ€ํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

์‚ฌ์šฉ์ž ์ •์˜ ๋งค์ฒ˜๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด expect.extend๋ฅผ ๋งํ•˜๋Š” ๊ฒƒ์€ "์—”์ง€๋‹ˆ์–ด๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์„ ๋‚ญ๋น„ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค."๋ผ๋Š” ์ฒซ ๋ฒˆ์งธ ์ฃผ์žฅ์—์„œ ํ”ผํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ๊ฒƒ๊ณผ ์ •ํ™•ํžˆ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์—ด๊ณ  ์ค„ ๋ฒˆํ˜ธ๋ฅผ ๋ณด๋Š” ๊ฒƒ์ด ์‰ฝ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์œผ๋ฏ€๋กœ OP์˜ ์œ ์Šค ์ผ€์ด์Šค๋Š” ๋‚˜๋ฅผ ๊ท€์ฐฎ๊ฒŒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋ฅผ ๊ดด๋กญํžˆ๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—ด๊ฑฐํ˜•์˜ ๋ชจ๋“  ๊ฐ’์„ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด ํ…Œ์ŠคํŠธ ๋‚ด๋ถ€์— ๋ฃจํ”„๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค.

it("Should contain at least one word of every wordType", () => {
  for (const wordType of wordTypes) {
    expect(words.find((word) => word.wordType === wordType)).toBeTruthy();
  }
});

์‹คํŒจํ•˜๋ฉด ์–ด๋–ค wordType ๊ฐ’์ด ์‹คํŒจํ–ˆ๋Š”์ง€ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

๋‚ด ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๊ฐ€ ํฌํ•จ๋œ ๋ฉ”์‹œ์ง€๋กœ ๋Œ€์ฒดํ•˜๊ณ  ๋ฉ”์‹œ์ง€์— ์˜ˆ์ƒ ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ(์˜ˆ: true)๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‹คํŒจํ•˜๋ฉด Jest๋Š” ์ถ”๊ฐ€ ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ ๋ฉ”์‹œ์ง€๋ฅผ ์ธ์‡„ํ•ฉ๋‹ˆ๋‹ค.

    expect(`${wordType} ${!!words.find((word) => word.wordType === wordType)}`).toEqual(`${wordType} ${true}`);

Jest๋Š” ์ด๊ฒƒ์„ ์ธ์‡„ํ•ฉ๋‹ˆ๋‹ค ...

expect(received).toEqual(expected)

Difference:

- Expected
+ Received

- 6 true
+ 6 false

... ์‹คํŒจํ–ˆ์„ ๋•Œ wordType์ด 6์ž„์„ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.

๋˜๋Š” ๋” ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ...

    if (!words.find((word) => word.wordType === wordType)) {
      expect(`Didn't find a word with wordType '${wordType}'`).toEqual(null);
    }

@cwellsx test.each ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜ํ™”๋œ ํ…Œ์ŠคํŠธ๋ฅผ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ wordType์ด ์„ค๋ช…์ ์ธ ์ œ๋ชฉ์ด ์žˆ๋Š” ๋…๋ฆฝ์ ์ธ ํ…Œ์ŠคํŠธ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค(๊ฐ’ ๊ธฐ๋ฐ˜).

์ด๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ…Œ์ŠคํŠธ์—์„œ ๋งค์šฐ ์œ ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

test("compare ArrayBufferCursors", () => {
    const orig: ArrayBufferCursor;
    const test: ArrayBufferCursor;

    expect(test.size).toBe(orig.size);

    while (orig.bytes_left) {
        expect(test.u8()).toBe(orig.u8());
    }
});

์ง€๊ธˆ์€ ArrayBufferCursor์˜ ์ผ๋ถ€ ๋ฐ”์ดํŠธ๊ฐ€ ์ž˜๋ชป๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ๋งŒ ์•Œ์ง€๋งŒ ์–ด๋Š ๋ฐ”์ดํŠธ์ธ์ง€๋Š” ๋ชจ๋ฆ…๋‹ˆ๋‹ค. ์ธ๋ฑ์Šค๋ฅผ ์ปจํ…์ŠคํŠธ๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ๋””๋ฒ„๊น…์ด ํ›จ์”ฌ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค. ๊ณ ๋ง™๊ฒŒ๋„ ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์€ ์—ฌ๊ธฐ์— ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ œ์‹œํ–ˆ์ง€๋งŒ ๋ชจ๋‘ ์ถ”ํ•˜๊ณ  ๋Š๋ฆฝ๋‹ˆ๋‹ค.

@rickhanlonii , ๋‚˜๋Š” ๋‹น์‹ ์ด jest์˜ ์œ ์ง€ ๊ด€๋ฆฌ ๋น„์šฉ์„ ์ค„์ด๊ณ  ์‹ถ์–ดํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€๋งŒ ๊ท€ํ•˜์˜ ์˜๊ฒฌ ์—์„œ ์ œ๊ณตํ•˜๋Š” ์˜ต์…˜์€ ๋‹ค๋ฅธ ๋ชจ๋“  ํ”„๋กœ์ ํŠธ์˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์œ ์ง€ ๊ด€๋ฆฌ๋ฅผ ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค. toEqual ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ assertion์„ ์„ค๋ช…ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ด ์ •๋„๋ฉด ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. ์ •๋ง ์ปค์Šคํ…€ ๋งค์ฒ˜๋ฅผ ์†Œ๊ฐœํ•˜๋Š” ๊ฑด๊ฐ€์š”?!

it.each ๊ฐ€ ์œ ์šฉํ•œ ๋ฐ˜๋ณต ํ…Œ์ŠคํŠธ์˜ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์ง€๋งŒ ์ฃผ์žฅ์— ๋Œ€ํ•œ ๊ฐ„๋‹จํ•œ ์ฃผ์„์— ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ด ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๊ฐ€ ๋” ๋ฌด๊ฑฐ์›Œ์ง‘๋‹ˆ๋‹ค.

์ด ํ† ๋ก ๊ณผ jest-expect-message ์˜ ์ถœํ˜„์€ Jasmine์˜ beforeAll ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ƒ๊ฐ๋‚˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค...

์—ฌ๊ธฐ์—์„œ OP์˜ ์š”์ฒญ์„ ์˜คํ•ดํ•˜๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ํ•ด๊ฒฐํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ๋ฌธ์ œ๋Š” ๊ฐ„๋‹จํ•œ try / catch ๋ฐ jest.expect ์ฃผ์œ„์˜ ๋ž˜ํผ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ํ•˜๊ณ  ์‹ถ์—ˆ๋˜ ๋ชจ๋“  ๊ฒƒ์€ ๋‚ด๊ฐ€ ๊ธฐ๋Œ€ํ–ˆ๋˜ ๊ฒƒ๊ณผ ๋‚ด๊ฐ€ ๋ฐ›์€ ๊ฒƒ๋“ค + ๊ทธ ์ค‘์š”์„ฑ์„ ์„ค๋ช…ํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋ณธ ๋กœ๊ทธ์˜ ์ „์ฒด๋ฅผ ๊ธฐ๋กํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋ฌผ๋ก  ์ด๊ฒƒ์€ ์›ํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ํ™•์žฅ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์˜ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ธ ๋ฒ„์ „์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

in some test utility file...

const myExpect = (expectFn, errorCallback) => {
  try {
    expectFn();
  } catch (err) {
    errorCallback();
    throw new Error(err);
  }
};

// in the actual test suite...

const context = { hello: "world", results, expected };
myExpect(
    () => expect(results).toEqual(expected),
    () => console.error("[Error] -- context:", JSON.stringify(context))
);

+1
์•ˆ๋…•ํ•˜์„ธ์š”, ์ €๋„ ์ด ๊ธฐ๋Šฅ์„ ์ •๋ง ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‚ด ์‚ถ์„ ํ›จ์”ฌ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“ค ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰