React TDD - 시작

박정호·2022년 8월 18일
0

TDD

목록 보기
2/6
post-thumbnail

TDD의 3가지 절차

실패

  • 실패하는 테스트 케이스를 먼저 만든다
  • 실패하는 테스트케이스를 만들 때는 프로젝트의 전체 기능에 대하여 처음부터 모든 테스트 케이스를 작성하는 것이 아니라, 지금 가장 먼저 구현할 기능 하나씩 테스트 케이스를 작성

성공

  • 우리가 작성하는 실패하는 테스트 케이스를 통과시키기 위하여, 코드를 작성하여 테스트를 통과시키는 것

리팩토링

  • 우리가 구현한 코드에 중복되는 코드가 있거나, 혹은 더 개선시킬 방법이 있다면 리팩토링을 진행
  • 리팩토링 이후에도 테스트케이스 성공하는지 확인
  • 이 절차가 끝나면 다음 기능 구현을 위해 새로운 실패하는 테스트 케이스 작성

최댓값 구하기

1. 실패한 테스트 케이스 작성.
-> 아직 테스트 케이스에 맞는 파일을 생성하지 않았으므로 stats.max 함수가 존재하지 않으니 TypeError: stats.max is not a function 이런 오류 발생

<stats.test.js>
const stats = require('./stats');

describe('stats', () => {
  it('gets maximum value', () => {
    expect(stats.max([1, 2, 3, 4])).toBe(4);
  });
});

2. 실패한 테스트 케이스를 성공하기 위한 코드 작성

<stats.js>
exports.max = numbers => {
  let result = numbers[0];
  numbers.forEach(n => {
    if (n > result) {
      result = n;
    }
  });
  return result;
};

3. 성공한 코드에서 리팩토링 진행

<stats.js>
exports.max = numbers => Math.max(...numbers);

최솟값 구하기

1. 실패한 테스트 케이스 작성.

<stats.test.js>
const stats = require('./stats');

describe('stats', () => {
  it('gets maximum value', () => {
    expect(stats.max([1, 2, 3, 4])).toBe(4);
  });
  it('gets minimum value', () => {
    expect(stats.min([1, 2, 3, 4])).toBe(1);
  });
});

2. 실패한 테스트 케이스를 성공하기 위한 코드 작성 + 리팩토링 된 코드

<stats.js>
exports.max = numbers => Math.max(...numbers);
exports.min = numbers => Math.min(...numbers);

평균값 구하기

1. 실패한 테스트 케이스 작성.

<stats.test.js>
const stats = require('./stats');

describe('stats', () => {
  it('gets maximum value', () => {
    expect(stats.max([1, 2, 3, 4])).toBe(4);
  });
  it('gets minimum value', () => {
    expect(stats.min([1, 2, 3, 4])).toBe(1);
  });
  it('gets average value', () => {
    expect(stats.avg([1, 2, 3, 4, 5])).toBe(3);
  });
});

2. 실패한 테스트 케이스를 성공하기 위한 코드 작성

<stats.js>
exports.max = numbers => Math.max(...numbers);
exports.min = numbers => Math.min(...numbers);
exports.avg = numbers => {
  const sum = numbers.reduce((acc, current) => acc + current, 0);
  return sum / numbers.length;
};

3. 성공한 코드에서 리팩토링 진행

<stats.js>
max, min 생략
exports.avg = numbers =>
  numbers.reduce(
    (acc, current, index, {array}) => acc + current / length,
    0
  );

잠깐)
1. reduce 함수 - 네개의 인자

  • 누산기 (acc)
  • 현재 값 (cur)
  • 현재 인덱스 (idx)
  • 원본 배열 (src)

2. 구조 분해 할당

  • 구조 분해 문법을 통해 array.length에서 위와 같이 {array}를 통해 중복코드 제거.
numbers.reduce(
    (acc, current, index, array) => acc + current / array.length,
    0
  );

배열 정렬하기

1. 실패한 테스트 케이스 작성.

  • toBe가 아닌 toEqual를 쓴 이유
    -> 객체 또는 배열을 비교해야하는 상황에 사용
  • describe 안에 describe 사용 가능. (it 내부에 it또는 describe 사용 X)
<stats.test.js>
const stats = require('./stats');

describe('stats', () => {
  it('gets maximum value', () => {
    expect(stats.max([1, 2, 3, 4])).toBe(4);
  });
  it('gets minimum value', () => {
    expect(stats.min([1, 2, 3, 4])).toBe(1);
  });
  it('gets average value', () => {
    expect(stats.avg([1, 2, 3, 4, 5])).toBe(3);
  });
  describe('median', () => {
    it('sorts the array', () => {
      expect(stats.sort([5, 4, 1, 2, 3])).toEqual([1, 2, 3, 4, 5]);
    });
  });
});

2. 실패한 테스트 케이스를 성공하기 위한 코드 작성

<stats.js>
max, min, avg생략
exports.sort = numbers => numbers.sort((a, b) => a - b);

중앙값 구하기

1. 실패한 테스트 케이스 작성.

  • toBe가 아닌 toEqual를 쓴 이유
    -> 객체 또는 배열을 비교해야하는 상황에 사용
  • describe 안에 describe 사용 가능. (it 내부에 it또는 describe 사용 X)
<stats.test.js>
const stats = require('./stats');

describe('stats', () => {
  it('gets maximum value', () => {
    expect(stats.max([1, 2, 3, 4])).toBe(4);
  });
  it('gets minimum value', () => {
    expect(stats.min([1, 2, 3, 4])).toBe(1);
  });
  it('gets average value', () => {
    expect(stats.avg([1, 2, 3, 4, 5])).toBe(3);
  });
  describe('median', () => {
    it('sorts the array', () => {
      expect(stats.sort([5, 4, 1, 2, 3])).toEqual([1, 2, 3, 4, 5]);
    });
    it('gets the median for odd length', () => {
      expect(stats.median([1, 2, 3, 4, 5])).toBe(3);
    });
    it('gets the median for even length', () => {
      expect(stats.median([1, 2, 3, 4, 5, 6])).toBe(3.5);
    });
  });
});

2. 실패한 테스트 케이스를 성공하기 위한 코드 작성

<stats.js>
max, min, avg생략
exports.sort = numbers => numbers.sort((a, b) => a - b);
exports.median = numbers => {
  const middle = Math.floor(numbers.length / 2);

  if (numbers.length % 2) {
    // 홀수
    return numbers[middle];
  }
  return (numbers[middle - 1] + numbers[middle]) / 2;
};

3. 성공한 코드에서 리팩토링 진행

<stats.js>
max, min, avg생략
exports.sort = numbers => numbers.sort((a, b) => a - b);
exports.median = numbers => {
  const { length } = numbers;
  const middle = Math.floor(length / 2);
  return length % 2
    ? numbers[middle]
    : (numbers[middle - 1] + numbers[middle]) / 2;

최빈값 구하기

  • 최빈값은 배열에서 가장 빈도가 높은 값. 이 값은 배열 안에 어떤 숫자들이 있느냐에 따라 형태가 다르다.

1번상황: 주어진 값들 중에서 가장 자주 나타난 값이 결과
[1,2,2,2,3] → 2
2번 상황: 모든 값들의 빈도가 똑같다면 최빈값은 없다
[1,2,3], [1,1,2,2,3,3] → null
3번 상황: 빈도가 똑같은 값이 여러개라면, 결과값도 여러개.
[1,2,2,3,3,4] → [2,3]

1. 실패한 테스트 케이스 작성.

  • toBe가 아닌 toEqual를 쓴 이유
    -> 객체 또는 배열을 비교해야하는 상황에 사용
  • describe 안에 describe 사용 가능. (it 내부에 it또는 describe 사용 X)
<stats.test.js>

const stats = require('./stats');

describe('stats', () => {
  it('gets maximum value', () => {
    expect(stats.max([1, 2, 3, 4])).toBe(4);
  });
  it('gets minimum value', () => {
    expect(stats.min([1, 2, 3, 4])).toBe(1);
  });
  it('gets average value', () => {
    expect(stats.avg([1, 2, 3, 4, 5])).toBe(3);
  });
  describe('median', () => {
    it('sorts the array', () => {
      expect(stats.sort([5, 4, 1, 2, 3])).toEqual([1, 2, 3, 4, 5]);
    });
    it('gets the median for odd length', () => {
      expect(stats.median([1, 2, 3, 4, 5])).toBe(3);
    });
    it('gets the median for even length', () => {
      expect(stats.median([1, 2, 3, 4, 5, 6])).toBe(3.5);
    });
  });
  describe('mode', () => {
  	//1번 상황
    it('has one mode', () => {
      expect(stats.mode([1, 2, 2, 2, 3])).toBe(2);
    });
    //2번 상황
    it('has no mode', () => {
      expect(stats.mode([1, 2, 3])).toBe(null);
    });
    //3번 상황
    it('has multiple mode', () => {
      expect(stats.mode([1, 2, 2, 3, 3, 4])).toEqual([2, 3]);
    });
  });
});

2. 실패한 테스트 케이스를 성공하기 위한 코드 작성

<stats.js>

max, min, avg, sort, median 생략

exports.mode = numbers => {
  const counts = new Map();
  numbers.forEach(n => {
    const count = counts.get(n) || 0;
    counts.set(n, count + 1);
  });
  
  //1번 상황
  const maxCount = Math.max(...counts.values());
  const modes = [...counts.keys()].filter(
    number => counts.get(number) === maxCount
  );
  //2번 상황
  if (modes.length === numbers.length) {
    // 최빈값이 없음
    return null;
  }
  //3번 상황
  if (modes.length > 1) {
    // 최빈값이 여러개
    return modes;
  }

  // 최빈값이 하나
  return modes[0];
};

3. 성공한 코드에서 리팩토링 진행

<stats.js>

max, min, avg, sort, median 생략

exports.mode = numbers => {
  const counts = numbers.reduce(
    (acc, current) => acc.set(current, acc.get(current) + 1 || 1),
    new Map()
  );
  
  const maxCount = Math.max(...counts.values());
  const modes = [...counts.keys()].filter(
    number => counts.get(number) === maxCount
  );

  if (modes.length === numbers.length) {
    // 최빈값이 없음
    return null;
  }

  if (modes.length > 1) {
    // 최빈값이 여러개
    return modes;
  }

  // 최빈값이 하나
  return modes[0];
};

참조: https://learn-react-test.vlpt.us/#/02-tdd-introduction

profile
기록하여 기억하고, 계획하여 실천하자. will be a FE developer (HOME버튼을 클릭하여 Notion으로 놀러오세요!)

0개의 댓글