๐Ÿค– ์ข‹์€ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ | Right-BICEP ์›์น™

๋ฆฌ๋ฒ„ riverยท2023๋…„ 11์›” 1์ผ
0
post-thumbnail

1. Right-BICEP ์›์น™์ด๋ž€ ?

"Right-BICEP"์€ ํšจ๊ณผ์ ์ธ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๊ธฐ๋ณธ ์›์น™๋“ค์„ ๋‚˜ํƒ€๋‚ด๋Š” ์•ฝ์–ด์ด๋ฉฐ, ํ…Œ์ŠคํŠธ๊ฐ€ ์ค‘์ ์„ ๋‘์–ด์•ผ ํ•˜๋Š” ํ•ต์‹ฌ ์˜์—ญ๋“ค์„ ๊ฐ•์กฐํ•œ๋‹ค.


1) R - Right (์ •ํ™•ํ•จ)


๐Ÿ’ฌย ย ์ƒํ™ฉ

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

๐Ÿ’ปย ย ์˜ˆ์‹œ ์ฝ”๋“œ

const { validateEmail } = require('./validation');

describe('Email Validation Tests', () => {
  test('should validate email address correctly', () => {
    expect(validateEmail('test@example.com')).toBeTruthy();
    expect(validateEmail('invalid-email')).toBeFalsy();
  });
});

// validation.js
function validateEmail(email) {
  const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return re.test(email);
}

module.exports = { validateEmail };
  • ์ด ์ฝ”๋“œ๋Š” ์ด๋ฉ”์ผ ์ฃผ์†Œ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ํ˜•์‹์ธ์ง€ ๊ฒ€์ฆํ•˜๋Š” validateEmail ํ•จ์ˆ˜์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค. ์œ ํšจํ•œ ์ด๋ฉ”์ผ ํ˜•์‹ ('test@example.com')๊ณผ ์œ ํšจํ•˜์ง€ ์•Š์€ ์ด๋ฉ”์ผ ํ˜•์‹ ('invalid-email')์— ๋Œ€ํ•œ ๊ฒ€์ฆ์„ ์ˆ˜ํ–‰ํ•จ์œผ๋กœ์จ, ์ด๋ฉ”์ผ ์ฃผ์†Œ์˜ ์ •ํ™•ํ•œ ํ˜•์‹์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ฒ€์ฆํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ์ด์ฒ˜๋Ÿผ ์ค‘์š”ํ•œ ์‚ฌํ•ญ์„ ์ •ํ™•ํžˆ ๊ฒ€์ฆํ•˜๋Š” ํ…Œ์ŠคํŠธ๋Š” ์†Œํ”„ํŠธ์›จ์–ด์˜ ์‹ ๋ขฐ์„ฑ์„ ๋†’์ด๋Š” ๋ฐ ๊ธฐ์—ฌํ•œ๋‹ค.

2) B - Boundary Conditions (๊ฒฝ๊ณ„ ์กฐ๊ฑด)


๐Ÿ’ฌย ย ์ƒํ™ฉ

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

๐Ÿ’ปย ย ์˜ˆ์‹œ ์ฝ”๋“œ

const { getLastItem } = require('./arrayUtil');

describe('Array Boundary Conditions Tests', () => {
  test('should handle empty array', () => {
    expect(getLastItem([])).toBeNull();
  });

  test('should return last item for non-empty array', () => {
    expect(getLastItem([1, 2, 3])).toBe(3);
  });
});

// arrayUtil.js
function getLastItem(array) {
  if (array.length === 0) return null;
  return array[array.length - 1];
}

module.exports = { getLastItem };
  • ์ด ์ฝ”๋“œ๋Š” ๋ฐฐ์—ด์˜ ๊ฒฝ๊ณ„ ์กฐ๊ฑด์„ ํ…Œ์ŠคํŠธํ•œ๋‹ค. getLastItem ํ•จ์ˆ˜๋Š” ์ฃผ์–ด์ง„ ๋ฐฐ์—ด์˜ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ, ๋นˆ ๋ฐฐ์—ด์ผ ๊ฒฝ์šฐ null์„ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค. Jest๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋นˆ ๋ฐฐ์—ด๊ณผ ๋น„์–ด ์žˆ์ง€ ์•Š์€ ๋ฐฐ์—ด ๋ชจ๋‘๋ฅผ ํ…Œ์ŠคํŠธํ•จ์œผ๋กœ์จ, ์ด ํ•จ์ˆ˜๊ฐ€ ๋ฐฐ์—ด์˜ ๊ฒฝ๊ณ„ ์กฐ๊ฑด์—์„œ๋„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ๊ฒ€์ฆํ•œ๋‹ค. ๊ฒฝ๊ณ„ ์กฐ๊ฑด์„ ํ…Œ์ŠคํŠธํ•จ์œผ๋กœ์จ ์†Œํ”„ํŠธ์›จ์–ด์˜ ๊ฒฌ๊ณ ํ•จ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.

3) I - Inverse Relationship (์—ญ ๊ด€๊ณ„)


๐Ÿ’ฌย ย ์ƒํ™ฉ

์—ญ ๊ด€๊ณ„ ํ…Œ์ŠคํŠธ๋Š” ์†Œํ”„ํŠธ์›จ์–ด์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„์ด ๋ฐ˜๋Œ€ ๋˜๋Š” ์ƒํ˜ธ ๋ณด์™„์ ์ธ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ถ”๊ฐ€(Add) ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•œ ํ›„, ์ œ๊ฑฐ(Remove) ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜์—ฌ ๋‘ ๊ธฐ๋Šฅ์ด ์„œ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ด์— ํ•ด๋‹นํ•œ๋‹ค.

๐Ÿ’ปย ย ์˜ˆ์‹œ ์ฝ”๋“œ

const { addItem, removeItem, getItems } = require('./listManager');

describe('List Inverse Relationship Tests', () => {
  test('adding and then removing an item should result in an empty list', () => {
    addItem('apple');
    removeItem('apple');
    expect(getItems()).toEqual([]);
  });
});

// listManager.js
let items = [];

function addItem(item) {
  items.push(item);
}

function removeItem(item) {
  const index = items.indexOf(item);
  if (index > -1) {
    items.splice(index, 1);
  }
}

function getItems() {
  return items;
}

module.exports = { addItem, removeItem, getItems };
  • ์ด ์ฝ”๋“œ์—์„œ๋Š” addItem์œผ๋กœ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๊ณ , removeItem์œผ๋กœ ๊ฐ™์€ ํ•ญ๋ชฉ์„ ์ œ๊ฑฐํ•œ ํ›„, getItems๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ตœ์ข… ๋ชฉ๋ก์ด ๋น„์–ด ์žˆ๋Š”์ง€ ๊ฒ€์ฆํ•œ๋‹ค. ์ด๋Ÿฐ ์—ญ ๊ด€๊ณ„ ํ…Œ์ŠคํŠธ๋Š” ์†Œํ”„ํŠธ์›จ์–ด์˜ ์„œ๋กœ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ๋“ค์ด ์ƒํ˜ธ ๋ณด์™„์ ์œผ๋กœ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฐ ์œ ์šฉํ•˜๋‹ค.

4) C - Cross-check (๊ต์ฐจ ๊ฒ€์ฆ)


๐Ÿ’ฌย ย ์ƒํ™ฉ

๊ต์ฐจ ๊ฒ€์ฆ์€ ์„œ๋กœ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๊ณ„์‚ฐํ•˜๊ฑฐ๋‚˜ ํ™•์ธํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋‘ ๊ฐ€์ง€ ๋‹ค๋ฅธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ ๋‘ ๊ฒฐ๊ณผ๋ฅผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด ๋ฐฉ์‹์œผ๋กœ, ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์ •ํ™•์„ฑ์„ ๋ณด๋‹ค ํ™•์‹คํ•˜๊ฒŒ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ’ปย ย ์˜ˆ์‹œ ์ฝ”๋“œ

const { sumDirect, sumIterative } = require('./sumCalculators');

describe('Sum Calculation Cross-Check Tests', () => {
  test('both sum calculation methods should return the same result', () => {
    const numbers = [1, 2, 3, 4, 5];
    expect(sumDirect(numbers)).toEqual(sumIterative(numbers));
  });
});

// sumCalculators.js
function sumDirect(numbers) {
  return numbers.reduce((a, b) => a + b, 0);
}

function sumIterative(numbers) {
  let sum = 0;
  for (let num of numbers) {
    sum += num;
  }
  return sum;
}

module.exports = { sumDirect, sumIterative };
  • ์ด ์ฝ”๋“œ์—์„œ๋Š” sumDirect ๋ฉ”์„œ๋“œ๊ฐ€ reduce ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐ์—ด์˜ ํ•ฉ์„ ๊ณ„์‚ฐํ•˜๊ณ , sumIterative ๋ฉ”์„œ๋“œ๋Š” ๋ฐ˜๋ณต๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๋‘ ๋ฉ”์„œ๋“œ๊ฐ€ ๋™์ผํ•œ ์ž…๋ ฅ์— ๋Œ€ํ•ด ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ Jest๋กœ ํ…Œ์ŠคํŠธํ•˜์—ฌ ๊ต์ฐจ ๊ฒ€์ฆํ•œ๋‹ค.

5) E - Error conditions (์˜ค๋ฅ˜ ์กฐ๊ฑด)


๐Ÿ’ฌย ย ์ƒํ™ฉ

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

๐Ÿ’ปย ย ์˜ˆ์‹œ ์ฝ”๋“œ

const { processData } = require('./dataProcessor');

describe('Error Conditions Test', () => {
  test('should handle invalid input gracefully', () => {
    expect(() => processData(null)).toThrow('Invalid input');
    expect(() => processData({})).toThrow('Invalid data structure');
  });

  test('should handle external service failure', async () => {
    // ์—ฌ๊ธฐ์„œ๋Š” ์™ธ๋ถ€ ์„œ๋น„์Šค ์‹คํŒจ๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํฌํ•จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    // ์˜ˆ๋ฅผ ๋“ค์–ด, Mock์ด๋‚˜ Spy๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜๋ฅผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ํ•  ์ˆ˜ ์žˆ๋‹ค.
    // ํ•ด๋‹น ๋ถ€๋ถ„์€ ํ”„๋กœ์ ํŠธ์™€ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๊ตฌํ˜„๋  ์ˆ˜ ์žˆ๋‹ค.
  });
});

// dataProcessor.js
function processData(data) {
  if (!data) {
    throw new Error('Invalid input');
  }
  // ... ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋กœ์ง ...
}

module.exports = { processData };
  • ์ด ์ฝ”๋“œ๋Š” processData ํ•จ์ˆ˜๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ž…๋ ฅ๊ฐ’์„ ๋ฐ›์•˜์„ ๋•Œ ์ ์ ˆํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š”์ง€ ํ…Œ์ŠคํŠธํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ์ข…๋ฅ˜์˜ ํ…Œ์ŠคํŠธ๋Š” ์˜ˆ์™ธ ์ƒํ™ฉ์—์„œ๋„ ์‹œ์Šคํ…œ์ด ๊ฒฌ๊ณ ํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•˜๋‹ค.

6) P - Performance characteristics (์„ฑ๋Šฅ ํŠน์„ฑ)


๐Ÿ’ฌย ย ์ƒํ™ฉ

์„ฑ๋Šฅ ํŠน์„ฑ ํ…Œ์ŠคํŠธ๋Š” ์†Œํ”„ํŠธ์›จ์–ด์˜ ์ฒ˜๋ฆฌ ์†๋„, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰, ๋””์Šคํฌ ๊ณต๊ฐ„ ์‚ฌ์šฉ ๋“ฑ์˜ ์„ฑ๋Šฅ ์ง€ํ‘œ๋ฅผ ํ‰๊ฐ€ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ API ์‘๋‹ต ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜๊ฑฐ๋‚˜, ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์‹œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ’ปย ย ์˜ˆ์‹œ ์ฝ”๋“œ

const { largeDataProcessor } = require('./processor');

describe('Performance Test', () => {
  test('should process data within acceptable time', () => {
    const largeData = generateLargeData(); // ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ ํ•จ์ˆ˜
    const startTime = performance.now();

    largeDataProcessor(largeData);

    const endTime = performance.now();
    const processingTime = endTime - startTime;

    expect(processingTime).toBeLessThan(1000); // 1000ms ์ด๋‚ด ์™„๋ฃŒ๋˜์–ด์•ผ ํ•จ
  });

  test('should not exceed memory limit', () => {
    const largeData = generateLargeData();

    const initialMemoryUsage = process.memoryUsage().heapUsed;
    largeDataProcessor(largeData);
    const finalMemoryUsage = process.memoryUsage().heapUsed;

    expect(finalMemoryUsage - initialMemoryUsage).toBeLessThan(100000000); // 100MB ์ด๋‚ด๋กœ ์ œํ•œ
  });
});

// processor.js
function largeDataProcessor(data) {
  // ... ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋กœ์ง ...
}

module.exports = { largeDataProcessor };
  • ์ด ์ฝ”๋“œ๋Š” ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ largeDataProcessor๊ฐ€ ์ •ํ•ด์ง„ ์‹œ๊ฐ„ ๋‚ด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ํŠน์ • ํ•œ๊ณ„๋ฅผ ๋„˜์ง€ ์•Š๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ๋Š” ์‹œ์Šคํ…œ์˜ ํšจ์œจ์„ฑ๊ณผ ํ™•์žฅ์„ฑ์„ ๊ฒ€์ฆํ•˜๋Š” ๋ฐ ์ค‘์š”ํ•˜๋‹ค.
profile
ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž

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

๊ด€๋ จ ์ฑ„์šฉ ์ •๋ณด