TDD(Test-driven Development)

rsuubinn·2023년 3월 31일
0

최적화

목록 보기
4/4

TDD(Test-driven Development)

: 코드를 작성하기 전에 테스트를 쓰는 소프트웨어 개발 방법론이다.
TDD를 통해 소프트웨어를 개발한다는 것은 작은 단위의 테스트 케이스를 작성하고, 이를 통과 하는 코드를 작성하는 과정을 반복하는 것을 의미한다.

  • Write Failing Test : 실패하는 테스트 코드를 먼저 작성한다.
  • Make Test Pass : 테스트 코드를 성공시키기 위한 실제 코드를 작성한다.
  • Refactor : 중복 코드 제거, 일반화 등의 리팩토링을 수행한다.

이 과정에서 1의 과정을 마치기 전에 2의 작업을 시작하지 않도록 주의해야 한다.
또한 2를 진행할 때에는, 1의 테스트를 통과할 정도의 최소 코드만 작성해야 한다.

TDD를 사용하는 이유

예상하지 못했던 버그를 줄여 소요 시간을 줄일 수 있기 때문이다.
개발 과정에서 코드는 다양한 조건에 의해 계속해서 삽입, 수정, 삭제된다.
이 과정에서 코드가 중복되거나 불필요한 코드가 남게 된다.
그리고 그로 인해 여러 가지 버그가 발생하거나, 디버깅 또한 어려워지는 현상이 발생하기도 한다.

테스트 코드를 작성하는 방법

console.log 를 사용하여 현재 작성한 코드가 어떤 결과물을 도출하는지 확인하는 것도 일종의 테스트이다.
여러 개발자들이 더 나은 테스트를 작성하기 위해 많은 테스트 오픈소스 프레임워크(mocha, chai 등)을 제작했다.
이를 이용하여 테스트를 한다.

과제 - Test Builder

detectNetwork.js

// detectNetwork.js

/**
 * 아래의 detectNetwork 함수는 어떤 카드 번호를 input으로 받아,
 * 카드 회사의 이름('MasterCard', 'American Express)을 return 하는 함수입니다.
 *
 * 예) detectNetwork('343456789012345') // 'American Express'
 *
 * 그럼 어떻게 카드 번호만 가지고, 카드회사를 알 수 있을까요?
 *
 * 2가지 방법이 있습니다.
 *  1. 앞 자리 숫자들 (이번 과제에서는 prefix라 부릅니다.)
 *  2. 숫자들의 길이 (이번 과제에서는 length라고 부릅니다.)
 */

function detectNetwork(cardNumber) {
  /**
   * 주의사항: 'cardNumber'는 항상 문자열입니다.
   * 'Diner's Club' 카드 번호는 항상 38이나 39로 시작을하고, 14 자리 숫자입니다.
   * 'American Express' 카드 번호는 항상 34 나 37로 시작하고, 15 자리 숫자입니다.
   * 이 글을 읽으셨다면, detectNetwork함수가 'Diner's Club', 'American Express'를
   * 정확히 검사할 수 있도록 만들고 브라우저 console 화면으로 돌아가세요.
   */

  let prefix = cardNumber.slice(0, 2);
  let length = cardNumber.length;

  if ((prefix === "38" || "39") && length === 14) {
    return "Diner's Club";
  }
  if ((prefix === "34" || "37") && length === 15) {
    return "American Express";
  }
  if (prefix[0] === "4" && (length === 13 || length === 16 || length === 19)) {
    return "Visa";
  }
  if (Number(prefix) >= 51 && Number(prefix) <= 55 && length === 16) {
    return "MasterCard";
  }
  if (
    (cardNumber.slice(0, 4) === "6011" ||
      prefix === "65" ||
      (Number(cardNumber.slice(0, 3)) >= 644 &&
        Number(cardNumber.slice(0, 3)) <= 649)) &&
    (length === 16 || length === 19)
  )
    return "Discover";
}

// you don't have to worry about this code. keep this code.

if (typeof window === "undefined") {
  module.exports = detectNetwork;
}

정규식 이용

/**
 * 아래의 detectNetwork 함수는 어떤 카드 번호를 input으로 받아,
 * 카드 회사의 이름('MasterCard', 'American Express)을 return 하는 함수입니다.
 *
 * 예) detectNetwork('343456789012345') // 'American Express'
 *
 * 그럼 어떻게 카드 번호만 가지고, 카드회사를 알 수 있을까요?
 *
 * 2가지 방법이 있습니다.
 *  1. 앞 자리 숫자들 (이번 과제에서는 prefix라 부릅니다.)
 *  2. 숫자들의 길이 (이번 과제에서는 length라고 부릅니다.)
 */

function detectNetwork(cardNumber) {
  /**
   * 주의사항: 'cardNumber'는 항상 문자열입니다.
   * 'Diner's Club' 카드 번호는 항상 38이나 39로 시작을하고, 14 자리 숫자입니다.
   * 'American Express' 카드 번호는 항상 34 나 37로 시작하고, 15 자리 숫자입니다.
   * 이 글을 읽으셨다면, detectNetwork함수가 'Diner's Club', 'American Express'를
   * 정확히 검사할 수 있도록 만들고 브라우저 console 화면으로 돌아가세요.
   */

  let dinnerRegex = /^3[89]\d{12}$/;
  let americanRegex = /^3[47]\d{13}$/;
  let visaRegex = /^4(?:\d{12}|\d{15}|\d{18})$/;
  let masterRegex = /^5[1-5]\d{14}$/;
  let discoverRegex = /^65|^6011|^64[4-9]/;

  if (dinnerRegex.test(cardNumber)) return "Diner's Club";
  else if (americanRegex.test(cardNumber)) return "American Express";
  else if (visaRegex.test(cardNumber)) return "Visa";
  else if (masterRegex.test(cardNumber)) return "MasterCard";
  else if (discoverRegex.test(cardNumber)) {
    if ([16, 19].indexOf(cardNumber.length) > -1) return "Discover";
  }
}

// you don't have to worry about this code. keep this code.

if (typeof window === "undefined") {
  module.exports = detectNetwork;
}

detectNetwork.test.js

// detectNetwork.test.js

/*
 * 이 파일을 어떻게 사용해야 하는지 STEP을 진행하다보면 알 수 있습니다.
 * 만일 그 전에 이 파일을 이용하고 싶다면 주석을 참고하여 직접 연구해야 합니다.
 */

/**
 * 11번 줄에 있는 FILL_ME_IN을 수정하실 필요는 없습니다.
 * 하지만 이 파일의 다른 곳에서 FILL_ME_IN을 보시게 된다면 다른 것으로 바꾸셔야합니다.
 */

let FILL_ME_IN = "Fill this value in";

describe("Introduction to Mocha Tests - READ ME FIRST", function () {
  // Mocha 테스트는 그저 다음 기능을 하는 도구입니다!
  // - 함수를 실행할 때 오류가 발생하면, 실패합니다.
  // - 오류가 발생하지 않으면, 실패하지 않습니다.
  // mocha에 대해 더 알고 싶다면 다음을 참고하세요. mochajs.org

  // 먼저 아래의 테스트를 수정해 테스트가 정상적으로 작동하도록 해주세요.
  // 그리고 Diner's club과 American Express 테스트로 넘어가주세요

  // it("오류가 발생하면 테스트가 실패합니다.", function() {
  //   throw new Error("저를 지워주세요!");
  // });

  it("오류가 발생하지 않으므로, 실패하지 않습니다.", function () {
    // 이 테스트는 실제로 아무것도 테스트하지 않습니다. 그러므로 그냥 여기는 통과하게 됩니다.
    let even = function (num) {
      return num % 2 === 0;
    };
    return even(10) === true;
  });

  // 우리는 테스트에서 예상 동작과 실제 동작을 비교하기를 원할 것입니다.
  // 예상 동작이 실제 동작과 다르다면, 테스트는 실패해야 합니다.
  it("예상 동작이 실제 동작과 일치하지 않을 때 오류가 발생합니다.", function () {
    let even = function (num) {
      return num % 2 === 0; // 체크하려는 함수에 뭔가 문제가 있군요!
    };

    if (even(10) !== true) {
      throw new Error("10은 짝수여야 합니다!");
    }
  });
});
/**
 * 아래의 테스트들은 detectNetwork 함수를 detectNetwork.js 파일로부터 불러와
 * 함수가 정상적으로 작동하는지 테스트합니다.
 * detectNetwork.js파일과 현재 파일을 수정해 모든 테스트가 통과하도록 만들어보세요.
 */
describe("Diner's Club", function () {
  // 주의하세요, 테스트에도 버그가 존재할 수 있습니다...

  it("has a prefix of 38 and a length of 14", function () {
    // throw new Error("Delete me!");

    if (detectNetwork("38345678901234") !== "Diner's Club") {
      throw new Error("Test failed");
    }
  });

  it("has a prefix of 39 and a length of 14", function () {
    if (detectNetwork("39345678901234") !== "Diner's Club") {
      throw new Error("Test failed");
    }
  });
});

describe("American Express", function () {
  // 항상 if/throw 구문으로 오류를 체크하는 것은 귀찮은 일이기 때문에,
  // 여기에 도움을 줄 수 있는 함수를 하나 제공했습니다. 입력값이 true가 아닐 경우 에러를 발생시킵니다.
  let assert = function (isTrue) {
    if (!isTrue) {
      throw new Error("Test failed");
    }
  };

  it("has a prefix of 34 and a length of 15", function () {
    assert(detectNetwork("343456789012345") === "American Express");
  });

  it("has a prefix of 37 and a length of 15", function () {
    assert(detectNetwork("373456789012345") === "American Express");
  });
});

describe("Visa", function () {
  // Chai는 테스트에 필요한 헬퍼 함수들이 담긴 라이브러리입니다!
  // Chai는 이전에 만들었던 assert 함수와 동일한 기능을 하는 assert 함수를 제공합니다.
  // Chai가 제공하는 assert 함수를 어떻게 사용하는지 웹사이트의 공식 문서를 참고해보세요.
  //   http://chaijs.com/
  let assert = chai.assert;

  it("has a prefix of 4 and a length of 13", function () {
    assert(detectNetwork("4123456789012") === "Visa");
  });

  it("has a prefix of 4 and a length of 16", function () {
    assert(detectNetwork("4123456789012345") === "Visa");
  });

  it("has a prefix of 4 and a length of 19", function () {
    assert(detectNetwork("4123456789012345678") === "Visa");
  });
});

describe("MasterCard", function () {
  // Chai는 좀 더 영어 문법에 가까운 코드로 테스트를 작성할 수 있게 도와줍니다.
  // Expect 문법은 그 중 한가지이며, 다른 문법도 있습니다.
  // 이와 관련해 더 알고 싶다면, 공식 문서를 참고하세요.
  //   http://chaijs.com/api/bdd/
  let expect = chai.expect;

  it("has a prefix of 51 and a length of 16", function () {
    expect(detectNetwork("5112345678901234")).to.equal("MasterCard");
  });

  it("has a prefix of 52 and a length of 16", function () {
    expect(detectNetwork("5212345678901234")).to.equal("MasterCard");
  });

  it("has a prefix of 53 and a length of 16", function () {
    expect(detectNetwork("5312345678901234")).to.equal("MasterCard");
  });

  // expect 대신에 should라는 문법을 사용해서 스타일을 조금 변경할 수도 있습니다.
  // 사실 둘 중 어떤 것을 사용하는지는 중요하지 않습니다.
  // 스타일에 관련해서는 다음 사이트를 참조하세요. http://chaijs.com/guide/styles/
  // 다만 중요한 것은 스타일의 일관성을 유지하는 것입니다.
  // (우리는 공부를 하는 중이기 때문에 두가지 방법 모두를 사용해 보았습니다.)
  // 테스트를 작성하는 중에, 두가지 방법을 동시에 사용하려고 하면 진행되지 않을 것입니다.
  // expect나 should 둘 중에 한가지 방법을 선택해서 사용하세요.
  let should = chai.should();

  it("has a prefix of 54 and a length of 16", function () {
    should.equal(detectNetwork("5412345678901234"), "MasterCard");
  });

  it("has a prefix of 55 and a length of 16", function () {
    should.equal(detectNetwork("5512345678901234"), "MasterCard");
  });
  for (let i = 51; i <= 55; i++) {
    it(`has a prefix of ${i} and a length of 16`, function () {
      should.equal(detectNetwork(`${i}12345678901234`), "MasterCard");
    });
  }
});

describe("Discover", function () {
  // 함수가 없는 테스트는 "pending"이라는 표시가 뜨며 실행되지 않습니다.
  // 아래 테스트를 작성하고 테스트가 통과하도록 만드십시오.
  let should = chai.should();
  it("has a prefix of 6011 and a length of 16", function () {
    should.equal(detectNetwork("6011123456789012"), "Discover");
  });
  it("has a prefix of 6011 and a length of 19", function () {
    should.equal(detectNetwork("6011123456789012345"), "Discover");
  });
  it("has a prefix of 65 and a length of 16", function () {
    should.equal(detectNetwork("6512345678901234"), "Discover");
  });
  it("has a prefix of 65 and a length of 19", function () {
    should.equal(detectNetwork("6512345678901234567"), "Discover");
  });
  for (let i = 644; i <= 649; i++) {
    it("has a prefix of " + i + " and a length of 16", function () {
      should.equal(detectNetwork(i.toString() + "1234567890123"), "Discover");
    });
    it("has a prefix of " + i + " and a length of 19", function () {
      should.equal(
        detectNetwork(i.toString() + "1234567890123456"),
        "Discover"
      );
    });
  }
});
profile
@rsuubinn

0개의 댓글