단언문과 테스트는 작성한 소프트웨어가 제대로 동작하는 지 확인할 수 있는 방법
14.1 단언문
: assert 메소드를 호출하는 방식으로 단언문 작성
: "assert(조건)" - 조건을 만족하지 않을 경우 AssertError 발생
: "assert(조건, 설명)" - 조건을 만족하지 않을 경우 설명을 포함한 AssertError 발생
def above(that: Element): Element = { val this1 = this widen that.width val that1 = that widen this.width assert(this1.width == that1.width) elem(this1.contents ++ that1.contents) } |
< ensuring 도우미 메소드 사용 >
private def widen(w: Int): Element = if (w <= width) this else { val left = elem(' ', (w - width) / 2, height) var right = elem(' ', w - width - left.width, height) left beside this beside right } ensuring (w <= _.width) |
: ensuring 인자는 술어 함수를 받는다.
: 술어 함수가 True를 반환하면 메소드 결과를 그대로 반환하고 False를 반환하면 AssertionError 발생
: "_"는 술어가 갖는 유일한 인자, 메소드가 반환해야 하는 결과가 들어간다.
: widen의 결과(Element)에 ensuring을 호출하고 있는 것 같지만 Element를 암시적으로 변환한 타입에 대해 ensuring 호출 = 암시적 변환을 사용하기 때문에 어떤 결과 타입이든 적용 가능
: JVM에 -ea나 -da 명령행 옵션을 사용하면 assert, ensuring 동작을 켜거나 끌 수 있다.
14.2 스칼라에서 테스트하기
: 스칼라는 스칼라테스트, 스펙스2, 스칼라체크 테스트 도구 존재
< 스칼라 테스트 >
: 가장 유연한 스칼라 테스트 프레임워크 => 테스트 관련 트레이트/클래스를 통해 쉽게 커스터마이징이 가능해 팀의 요구에 맞는 테스트 스타일 사용 가능
- 트레이트 Suite : 테스트들을 실행하기 위해 사전에 준비된 '생명 주기' 메소드가 선언되어 있음
- 스타일 트레이트 : 다른 테스트 스타일을 지원하기 위해 트레이트 Suite를 확장해 생명 주기 메소드 오버라이드
- 믹스인 트레이트 : 특별한 테스트 요구를 해결하기 위해 생명 주기 메소드 오버라이드
=> 스타일 트레이트와 믹스인 트레이트를 통해 테스트 클래스를 정의해 테스트 스위트(테스트 집합)를 만든다.
import org.scalatest.FunSuite import Element.elem
class ElementSuite extends FunSuite { test("elem result should have passed width") { val ele = elem('x', 2, 3) assert(ele.width == 2) } } |
: FunSuite 스타일 트레이트는 test 메소드 안에 테스트 코드 작성
: test는 이름에 의한 호출 파라미터로 주 생성자에서 테스트 코드를 나중에 실행하기 위해 등록
: 인터프리터에서 단순히 execute를 호출함으로써 테스트 실행
scala> (new ElementSuite).execute() ElementSuite: - elem result should have passed width |
14.3 충분한 정보를 제공하는 실패 보고
< 기본 내장 assert > val a = 3 assert(a==2) |
< scalatest assert > val a = 3 assert(a==2) |
: 스칼라 테스트는 컴파일 시점에 각 assert 호출에 전달된 식 분석 => 상세한 정보 및 서술적인 오류 메시지 출력
: 실제와 기대치가 다르다는 사실을 강조하고 싶다면 assertResult 사용
val width = 3 assertResult(2) { width } |
: 어떤 메소드가 발생시킬 수 있는 예외를 검사하고 싶다면 assertThrows 사용
assertThrows[ArithmeticException] { throw new AbstractMethodError } |
: assertThrows 는 정상적인 예외에 대해 Succeeded라는 단순한 결과를 반환하지만 intercept는 예외 자체를 반환
14.4 명세로 테스트하기
- 동작 주도 개발( BDD - behavior-driven development ) 테스트 스타일 : 기대하는 코드의 동작을 사람이 읽을 수 있는 명세로 작성하고 코드가 그 명세에 따라 작동하는지 확인하는 테스트를 작성하는 데 중점(요구사항[스펙, 명세]이 테스트 코드가 되고 이 테스트 코드를 기반으로 기능 구현)
import org.scalatest.FlatSpec it should "throw an IAE if passed a negative width" in { |
: FlatSpec 스타일 트레이트를 사용하면 BDD 테스트 스타일로 작성 가능
: 형식 => 테스트 주제 should(must, can) 테스트 설명 in { 테스트 코드 }
: it 은 가장 최근에 언급된 테스트 주제 의미 => it은 "A UniformElement"
: "should be", "in", "should be thrownBy" 문법은 ShouldMatchers(연결자 도메인 특화 언어) 믹스인 트레이트에서 제공
=> should 보다 must를 선호한다면 MustMatchers를 믹스인
=> 연결자 DSL을 통해 커스텀하게 단언문 작성 가능
scala> (new ElementSpec).execute() A UniformElement - should have a width equal to the passed value - should throw an IAE if passed a negative width |
: 실행 시 사람이 읽기 더 좋은 출력을 만든다.
- BDD는 소프트웨어 시스템을 만들지 결정하는 사람, 그 소프트웨어를 구현하는 사람, 소프트웨어가 잘 마무리되어 동작하는 지 결정하는 사람 사이의 의사소통을 테스트가 도와주도록 해야 한다.
import org.scalatest._ class TVSetSpec extends FeatureSpec with GivenWhenThen { feature("TV power button"){ scenario("User presses power button when TV is off"){ Given("a TV set that is switched off") When("the power button is pressed") Then("the TV sould switch on") pending } } } |
: FeatureSpec 스타일 트레이트는 의사소통을 돕기 위해 설계
: 구체적인 특징(feature)을 밝혀야 하고 그에 대한 시나리오(scenario)를 명시한다.
: Given, When, Then 은 구체적인 개별 시나리오에 대한 대화에 초점을 맞춘다.
: pending 호출은 테스트나 실제 동작이 아직 구현되지 않았다는 사실 명시
14.5 프로퍼티 기반 테스트
: 스칼라 체크는 각 프로퍼티에 대해 테스트 데이터를 생성한 다음, 프로퍼티를 잘 지키는지 검사하는 테스트를 실행
import org.scalatest.WordSpec import org.scalatest.MustMatcers._ |
: elem 요소가 지켜야 하는 한 가지 프로퍼티 검사
: whenever은 왼쪽 편에 있는 절이 true일 때마다 오른쪽에 있는 식이 true가 되어야함을 명시한다.
: forAll 내부에 테스트 데이터를 인자로 받고 단언문을 수행하는 함수값 명시 => 스칼라 체크가 테스트 데이터를 임의로 수 백개 생성 => 모든 값을 만족하는 경우 테스트를 통과 그렇지 않는 경우 실패 원인이 된 값이 들어있는 TestFailedException을 던지고 종료
14.6 테스트 조직과 실행
: 스칼라 테스트는 스위트 안에 스위트를 포함시킴으로써 큰 테스트를 조직 => 트리 구조를 형성해 루트 Suite 객체를 실행하면 트리 전체의 Suite를 실행한다.
: 수동 또는 자동으로 스위트 포함 가능
- 수동 : nestedSuites 메소드 오버라이드 또는 생성자에 Suite 전달
import org.scalatest.Suite
scala> (new AlphabetSuite).run() |
- 자동 : 스칼라 테스트의 Runner에 패키지 이름 전달
$ scalac -cp scalatest.jar TVSetSpec.scala $ scala -cp scalatest.jar org.scalatest.run TVSetSpec |
'스칼라' 카테고리의 다른 글
스칼라 16장 리스트(Programming in Scala, 3rd) (0) | 2019.06.02 |
---|---|
스칼라 15장 케이스 클래스와 패턴 매치(Programming in Scala, 3rd) (0) | 2019.06.02 |
스칼라 13장 패키지와 임포트(Programming in Scala, 3rd) (0) | 2019.06.01 |
스칼라 12장 트레이트(Programming in Scala, 3rd) (0) | 2019.06.01 |
스칼라 11장 스칼라의 계층 구조(Programming in Scala, 3rd) (0) | 2019.06.01 |