Mar 29, 2021, TIL (Today I Learned) - TDD

Inwoo Hwang·2021년 8월 26일
0
post-thumbnail

수업 내용


TDD [Test Driven Development]

테스트 주도 개발이란?

테스트주도 개발(Test-driven Development TDD)은 매우 짧은 개발 사이클을 반복하는 소프트웨어 개발 프로세스 중 하나이다. 개발자는 먼저 요구사항을 검증하는 자동화된 테스트 케이스를 작성한다. 그런 후에 그 테스트 케이스를 통과하기 위한 최소한의 코드를 생성한다. 마지막으로 작성한 코드를 표준에 맞도록 리펙토링한다.

[출처] 위키백과, 우리 모두의 백과사전

테스트 주도 개발 Cycle

  • Writing a Failing Test
  • Write just enough code to pass it
  • Change code for better without chaning the behavior

*빠르게 실패하고 피드백을 받고 개선하자. 작은 실패를 반복하면 결국에는 원하는 목표를 이룰 수 있습니다.

객체지향 생활 체조 훈련법 9가지

  1. 메서드당 들여쓰기는 한번 [예] if 안에 if 작성 금지
  2. else 예약어 사용금지
  3. 원시값과 문자열의 포장
  4. 한줄에 한점만 사용 (메서드 체이닝 사용금지)
  5. 줄여쓰지 않는다. 축약 금지
  6. 모든 엔티티는 작게
  7. 2개 이상의 인스턴스 변수를 가진 클래스 사용금지
  8. 일급 콜렉션 사용
  9. getter/setter/속성 사용 금지 (프로퍼티에 직접 접근하지 말기)

어떤 테스트를 작성해야 할까? 🙋

  • 결과가 올바른지? ✅
  • 모든 경계(boundary) 조건이 올바른지 ✅
  • 역(inverse)관계를 확인할 수 있나? ✅
  • 다른 수단을 사용해서 결과를 교차 확인(cross-check) 할 수 있나? ✅
  • 에러 조건(error condition)을 강제로 만들 수 있나? ✅
  • 성능(performance) 특성이 한도내에 있나? ✅

그리고 테스트는

  • Fast
  • Independent
  • Repeatable
  • Self-Validating
  • Timely

하게 진행되어야 한다.[FIRST]!!!

그럼 테스트를 어떻게 하지?

유닛 테스트를 활용하자!

유닛 테스트는 컴퓨터 프로그래밍에서 소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차다. 즉, 모든 함수와 메소드에 대한 테스트 케이스를 작성하는 절차를 말한다. 이를 통해서 언제라도 코드 변경으로 인해 문제가 발생하는 경우, 단시간 내에 이를 파악하고 바로 잡을 수 있도록 해준다. 이상적으로, 각 테스트 케이스는 서로 분리되어야 한다.

[출처] 위키백과, 우리 모두의 백과사전

↓↓iOS의 유닛테스트에 대한 자세한 내용은 아래 링크에서 확인할 수 있다↓↓

iOS Unit Testing and UI Testing Tutorial | raywenderlich.com

테스트 관련 용어

  • SUT[System Under Test]: 테스트 대상 또는 시스템[모듈]을 뜻한다.
  • Test Doubles: 오리지널 객체를 사용해서 테스트를 진행하기 어려운 경우 이를 대신해서 테스트를 진행할 수 있도록 만들어 주는 객체를 지칭하는 용어이다.

learn more about Test Doubles ↓↓

Test Double(테스트 더블)알아보기 (tistory.com)

학습 내용


나만의 연산자를 만들자

NAND, NOR과 같은 연산이 필요해서 찾아봤는데 그런 연산자는 기본으로 지원 해 주지 않더라구요...

그래서 만들어 봤습니다🤩

infix operator ~& : MultiplicationPrecedence
infix operator ~| : AdditionPrecedence

위와 같이 infix operator 선언을 한 뒤 연산자 순위 설정을 해주면 일단 절반 완성 되었습니다. 😁

커스텀연산자를 사용하려면 전역변수로 설정을 해야합니다. 이 부분만 유의하시면 좋을 것 같아요.

func ~& (lhs: UInt8, rhs: UInt8) -> UInt8 {
    return ~lhs | ~rhs
}

func ~| (lhs: UInt8, rhs: UInt8) -> UInt8 {
    return ~lhs & ~rhs
}

그리고 각각의 연산자가 행할 기능을 전역 메서드로 선언 해 주면 끝입니다🔥

그럼 다른 메서드 안에서 사용할 수 있더라구요. 이렇게요!

 func calculatePostfixNotation() {
   ...
   switch element {
   case "~&" :
     operandStack.push(Int(firstBinaryNumber ~& secondBinaryNumber))
   case "~|" :
     operandStack.push(Int(firstBinaryNumber ~| secondBinaryNumber))
   default:
     return
   }
 }

내가 필요한 조건에 맞는 연산이 필요할 때 이렇게 커스텀 연산자를 사용하면 좋을 것 같습니다!!💪

고민한 내용/ 해결한 내용


계산기 코드를 조금 더 객체지향적으로 설계할 수 없을까 고민하고 있습니다.

지금 코드는 중복되는 부분도 많고 설계가 생각보다 더 복잡한 부분도 있는 것 같아서 고민입니다.

아직 해결은 못했으나 리뷰어에게 받은 피드백을 적극 반영하여 차근차근 해결 해 나가려 합니다 😅

profile
james, the enthusiastic developer

0개의 댓글