[ 코드잇 스프린트 ] 교육기간 7일차 TIL

2024. 11. 16. 23:50·교육/코드잇 스프린트 : 단기심화 5기


강의 목표

강의시간에 학습한 내용을 정리합니다.

 

강의 내용 정리

강의시간에 학습한 내용을 정리합니다.

 

실습 - Matcher를 이용해 유닛 테스트 작성하기 1

  • 기존 next.js 프로젝트 계속 사용
  • 다음 링크 참조하여 jest 설치 및 실행 환경 설정
  • 테스트할 함수는 아래 코드를 참조
  • 루트 위치에 /utils/chunk.ts 파일 생성 후 위 링크의 코드 복사
  • chunk.ts 파일과 같은 경로에 chunk.test.ts 파일 생성 후 테스트 코드 작성
  • 테스트를 실행시키기 위해 프로덕션 코드에 약간의 변경 필요
  • chunk 함수의 파라미터와 관련하여 코드가 수정될 부분 존재
    -> 이 약점(버그) 찾아서 테스트 코드 작성하고 프로덕션 코드도 수정
// 테스트할 코드
/**
 * 'size' 길이만큼 그룹으로 분할된 요소 배열을 만듭니다. `배열`을 균등하게 분할할 수 없는 경우 
 *  최종 청크는 나머지 요소가 됩니다.
 *
 * @param {Array} array 배열을 처리할 대상
 * @param {number} [size=1] 분할할 크기
 * @returns {Array} 새로운 배열을 반환
 * @example
 *
 * chunk(['a', 'b', 'c', 'd'], 2)
 * // => [['a', 'b'], ['c', 'd']]
 *
 * chunk(['a', 'b', 'c', 'd'], 3)
 * // => [['a', 'b', 'c'], ['d']]
 */

function chunk(array: any[], size: number = 1) {
  size = Math.max(size, 0);
  const length = array == null ? 0 : array.length;
  if (!length || size < 1) {
    return [];
  }
  let index = 0;
  let resIndex = 0;
  const result = new Array(Math.ceil(length / size));

  while (index < length) {
    result[resIndex++] = array.slice(index, (index += size));
  }
  return result;
}
// 정답코드
import { chunk } from "./chunk";

describe("chunk", () => {
  const array = [0, 1, 2, 3, 4, 5];

  it("should return chunked arrays", () => {
    const actual = chunk(array, 3);
    expect(actual).toEqual([
      [0, 1, 2],
      [3, 4, 5],
    ]);
  });

  it("should return the last chunk as remaining elements", () => {
    const actual = chunk(array, 4);
    expect(actual).toEqual([
      [0, 1, 2, 3],
      [4, 5],
    ]);
  });

  it("should coerce `size` to an integer", () => {
    expect(chunk(array, array.length / 4)).toEqual([
      [0],
      [1],
      [2],
      [3],
      [4],
      [5],
    ]);
  });
});

 

 

실습- Matcher를 이용해 유닛 테스트 작성하기 2

// 테스트할 코드

const htmlEscapes: Record<string, string> = {
  "&": "&amp;",
  "<": "&lt;",
  ">": "&gt;",
  '"': "&quot;",
  "'": "&#39;",
};

const htmlUnescapes: Record<string, string> = {
  "&amp;": "&",
  "&lt;": "<",
  "&gt;": ">",
  "&quot;": '"',
  "&#39;": "'",
};

const reUnescapedHtml = /[&<>"']/g;
const reHasUnescapedHtml = RegExp(reUnescapedHtml.source);

const reEscapedHtml = /&(?:amp|lt|gt|quot|#(0+)?39);/g;
const reHasEscapedHtml = RegExp(reEscapedHtml.source);

/**
 * 문자 "&", "<", ">", '"' 및 "'"를 해당 HTML 엔터티로 변환합니다.
 *
 * @param {string} [string=''] 변환할 문자열.
 * @returns {string} 변환된 문자열을 반환합니다.
 * @example
 *
 * escape('fred, barney, & pebbles')
 * // => 'fred, barney, &amp; pebbles'
 */
function escape(string: string) {
  return string && reHasUnescapedHtml.test(string)
    ? string.replace(reUnescapedHtml, (chr) => htmlEscapes[chr])
    : string || "";
}

/**
 * 이 메서드는 `escape`의 역으로 `string`의 HTML 엔터티 `&amp;`, `<`, `&gt;`, `&quot;` 및 
 * `&#39;`를 해당 문자로 변환합니다.
 *
 * @param {string} [string=''] 변환할 문자열.
 * @returns {string} 변환된 문자열을 반환합니다.
 * @example
 *
 * unescape('fred, barney, &amp; pebbles')
 * // => 'fred, barney, & pebbles'
 */
function unescape(string: string) {
  return string && reHasEscapedHtml.test(string)
    ? string.replace(reEscapedHtml, (entity) => htmlUnescapes[entity] || "'")
    : string || "";
}

export { escape, unescape };
// 정답 코드

import { escape, unescape } from "./htmlEscape";

describe("escape", () => {
  let escaped = "&amp;&lt;&gt;&quot;&#39;/";
  let unescaped = "&<>\"'/";

  escaped += escaped;
  unescaped += unescaped;

  it("should escape values", () => {
    expect(escape(unescaped)).toBe(escaped);
  });

  it("should handle strings with nothing to escape", () => {
    expect(escape("abc")).toBe("abc");
  });

  it("should escape the same characters unescaped by `_.unescape`", () => {
    expect(escape(unescape(escaped))).toBe(escaped);
  });

  ["`", "/"].forEach((chr) => {
    it(`should not escape the "${chr}" character`, () => {
      expect(escape(chr)).toBe(chr);
    });
  });
});

describe("unescape", () => {
  let escaped = "&amp;&lt;&gt;&quot;&#39;/";
  let unescaped = "&<>\"'/";

  escaped += escaped;
  unescaped += unescaped;

  it("should unescape entities in order", () => {
    expect(unescape("&amp;lt;")).toBe("&lt;");
  });

  it("should unescape the proper entities", () => {
    expect(unescape(escaped)).toBe(unescaped);
  });

  it("should handle strings with nothing to unescape", () => {
    expect(unescape("abc")).toBe("abc");
  });

  it("should unescape the same characters escaped by `_.escape`", () => {
    expect(unescape(escape(unescaped))).toBe(unescaped);
  });

  it("should handle leading zeros in html entities", () => {
    expect(unescape("&#39;")).toBe("'");
    expect(unescape("&#039;")).toBe("'");
    expect(unescape("&#000039;")).toBe("'");
  });

  ["&#96;", "&#x2F;"].forEach((entity) => {
    it(`should not unescape the "${entity}" entity`, () => {
      expect(unescape(entity)).toBe(entity);
    });
  });
});

 

 

실습- .not 수식어를 이용해 유닛 테스트 작성하기

  • 기존 next.js 프로젝트 계속 사용
  • 함수의 명세를 잘 읽고 필요한 테스트들 작성
    -> .not 수식어를 사용하는 테스트도 작성할 것
// 테스트할 코드

/**
 * 섞인 값의 배열을 만듭니다.
 *
 * @param {Array} array 작업을 처리할 배열
 * @returns {Array} 새로운 배열을 반환
 * @example
 *
 * shuffle([1, 2, 3, 4])
 * // => [4, 1, 3, 2]
 */
function shuffle(array: any[]) {
  const length = array == null ? 0 : array.length;
  if (!length) {
    return [];
  }
  let index = -1;
  const lastIndex = length - 1;
  const result = [...array];
  while (++index < length) {
    const rand = index + Math.floor(Math.random() * (lastIndex - index + 1));
    const value = result[rand];
    result[rand] = result[index];
    result[index] = value;
  }
  return result;
}

export default shuffle;
// 정답 코드

import shuffle from "./shuffle";

describe("shuffle", () => {
  const array = [1, 2, 3];

  it("should return a new array", () => {
    expect(shuffle(array)).not.toBe(array);
  });

  it("should contain the same elements after a collection is shuffled", () => {
    expect(shuffle(array).sort()).toEqual(array);
  });
});

 

 

실습 - 비동기 코드 유닛 테스트 작성하기

  • 기존 next.js 프로젝트 계속 사용
  • 함수의 명세를 잘 읽고 필요한 테스트들 작성
    • done 인자를 이용해 작성할 것
    • mock 함수(jest.fn())와 toHaveBeenCalledWith matcher를 이용한 함수도 작성할
// 테스트할 코드

/**
 * 'wait' 밀리초 후에 'func'를 호출합니다.
 *
 * @param {Function} func 호출할 함수.
 * @param {number} wait 지연할 밀리초.
 * @param {...*} [args] 함수에 전달할 인수.
 * @returns {number} 타이머 ID.
 * @example
 *
 * delay(text => console.log(text), 1000, 'later')
 * // => Logs 'later' after one second.
 */
function delay(func: Function, wait = 0, ...args: any[]) {
  if (typeof func !== "function") {
    throw new TypeError("Expected a function");
  }
  return setTimeout(func, +wait, ...args);
}

export default delay;
// 정답 코드

import delay from "./delay";

describe("delay", () => {
  it("should delay `func` execution", (done) => {
    let pass = false;
    delay(() => {
      pass = true;
    }, 32);

    setTimeout(() => {
      expect(pass).toBe(false);
    }, 1);

    setTimeout(() => {
      expect(pass);
      done();
    }, 64);
  });

  it("should use a default `wait` of `0`", (done) => {
    let pass = false;
    delay(() => {
      pass = true;
    });

    expect(pass).toBe(false);

    setTimeout(() => {
      expect(pass);
      done();
    }, 0);
  });

  it("should be cancelable", (done) => {
    let pass = true;
    const timerId = delay(() => {
      pass = false;
    }, 32);

    clearTimeout(timerId);

    setTimeout(() => {
      expect(pass);
      done();
    }, 64);
  });

  it("should provide additional arguments to `func`", (done) => {
    const mockFn = jest.fn();

    delay(mockFn, 32, 1, 2);

    setTimeout(() => {
      expect(mockFn).toHaveBeenCalledWith(1, 2);
      done();
    }, 64);
  });
});
반응형
저작자표시 비영리 변경금지 (새창열림)

'교육 > 코드잇 스프린트 : 단기심화 5기' 카테고리의 다른 글

[ 코드잇 스프린트 ] 교육기간 9일차 TIL  (1) 2024.11.21
[ 코드잇 스프린트 ] 교육기간 8일차 TIL  (1) 2024.11.18
[ 코드잇 스프린트 ] 교육기간 6일차 TIL  (3) 2024.11.15
[ 코드잇 스프린트 ] 교육기간 5일차 TIL  (1) 2024.11.14
[ 코드잇 스프린트 ] 교육기간 4일차 TIL  (3) 2024.11.13
'교육/코드잇 스프린트 : 단기심화 5기' 카테고리의 다른 글
  • [ 코드잇 스프린트 ] 교육기간 9일차 TIL
  • [ 코드잇 스프린트 ] 교육기간 8일차 TIL
  • [ 코드잇 스프린트 ] 교육기간 6일차 TIL
  • [ 코드잇 스프린트 ] 교육기간 5일차 TIL
heee1
heee1
FE 개발자를 희망하는 임희원 입니다.
  • heee1
    heee1.blog
    heee1
  • 전체
    오늘
    어제
    • 분류 전체보기 (69)
      • Front-end (1)
        • Javascript (4)
        • Typescript (1)
        • React (0)
        • Next.js (1)
        • Tool (1)
        • Git (1)
        • Prettier (0)
        • Test-Framework (1)
        • Vercel (1)
      • 교육 (28)
        • 항해99 : 웹개발 종합반 18기 (14)
        • 프로젝트 캠프 : React 2기 (5)
        • 코드잇 스프린트 : 단기심화 5기 (9)
      • Algorithm (29)
        • Javascript (24)
        • Python (5)
      • 코드 보관함 (1)
        • 배치스크립트 ( .bat ) (1)
  • 블로그 메뉴

    • 홈
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    자바스크립트
    til
    tailwindcss
    항해99
    node.js
    백준
    JavaScript
    코드잇
    next.js
    오블완
    Baekjoon
    jest
    speed insights
    스프린트
    Python
    테스트 프레임워크
    react-spring
    css animation
    티스토리챌린지
    모킹
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
heee1
[ 코드잇 스프린트 ] 교육기간 7일차 TIL
상단으로

티스토리툴바