ScalaTest에서는 테스트 결과를 검증하기 위해서 assert와 함께 should, shouldBe, must, mustBe 등의 assert 함수를 제공해줍니다.
should나 must 등의 함수는 내부적으로 assert와 동일하지만, 문장을 이해하기 쉽게 해주기 위한 syntax sugar 역할로 이해하면 됩니다.
should, must도 동일하게 동작하지만 테스트 결과의 뉘앙스 차이를 주는 것이니 원하는 문장을 사용하면 됩니다.
Assertion
assert를 적용하기 위한 방법은 trait, import의 두 가지 방법이 있습니다.
trait를 사용하는 것이 조금 더 보편적이고, import를 사용해도 크게 상관없습니다.
import org.scalatest.funspec.AnyFunSpec
import org.scalatest.matchers.should.Matchers
class SetRefSpec extends AnyFunSpec with Matchers {
describe("Set이 비었을경우") {
it("headOption 호출 시 None을 반환한다") {
// given
val set = Set.empty[Int]
// when
val actual = set.headOption
// then
actual should be (None)
}
}
}
should trait를 사용하고 싶다면 "org.scalatest.matchers.should.Matchers"를 사용하면 되고, must trait를 사용하고 싶다면 "org.scalatest.matchers.must.Matchers"를 사용하면 됩니다.
Matchers style
scala test는 5가지 matchers style을 제공해줍니다
result should equal (3) // equality를 수정할 수 있습니다
result should === (3) // equality를 수정할 수 있고, type 역시 고정할 수 있습니다
result should be (3) // equality를 수정할 수 없지만 그만큼 컴파일 속도가 빠릅니다
result shouldEqual 3 // equality를 수정할 수 있고 괄호가 필요 없습니다
result shouldBe 3 // equality를 수정할 수 없지만 그만큼 컴파일 속도가 빠르고 괄호가 필요 없습니다
일반적으로는 가장 마지막의 shouldBe를 사용해서 case class의 equality 비교를 수행합니다.
배열 비교
배열을 비교한다면 크기 비교, 전체 비교를 수행할 때 다음과 같이 비교합니다.
// length 크기 비교
result should have length 10
// size 크기 비교
result should have size 10
// 전체 일치 비교
result shouldBe Array(1, 2, 3, 4, 5)
문자열 비교
문자열을 비교한다면 처음의 일부분 일치, 끝의 일부분 일치, 일부 포함 등 함수를 사용해 비교할 수 있습니다.
// Hello로 시작하는지 비교
string should startWith ("Hello")
// world로 끝나는지 비교
string should endWith ("world")
// seven 문자열을 포함하는지 비교
string should include ("seven")
// regex 매치 비교
string should startWith regex "Hel*o"
string should endWith regex "wo*lo"
string should include regex "se.en"
string should fullyMatch regex """(-)?(\d+)(\.\d*)?"""
대소 비교
객체가 implicit ordering[T]를 지원할 때 부등호를 이용해 대소를 비교할 수 있습니다
one should be < 7
one should be > 0
one should be <= 7
one should be >= 0
타입 비교
타입 비교를 하고 싶다면 a 함수를 사용하면 됩니다.
JVM은 타입 파라미터를 지우기 때문에 List 같은 타입 파라미터를 지니는 타입은 타입 파라미터 비교가 의미 없기에 _ 를 이용해 비교하는 것이 좋습니다.
result1 shouldBe a[Int]
result2 shouldBe a[List[_]]
Collection 비교
ScalaTest는 collection 비교에 사용 가능한 다양한 함수들을 제공해줍니다.
// 빈 배열 비교
List() shouldBe empty
// 비어있지 않은 배열 비교
List(1) should not be empty
// 일부 포함 비교
List(1) should contain (1)
// 비교 대상에 오직 하나만 포함 비교
// 만약 1, 4, 5 중 둘 이상이 비교 원본에 포함될경우 테스트가 실패한다
List(1, 2, 3) should contain oneOf (1, 4, 5)
// 하나도 포함 안함 비교
List(1, 2, 3) should contain noneOf (7, 8, 9)
// 이 외에도 다양한 비교가 존재하니 https://www.scalatest.org/user_guide/using_matchers 참조
case class 비교
case class를 비교한다면 shouldBe, mustBe 매칭을 사용하는 것이 편합니다.
만약 일부 필드만 비교를 원한다면 have 함수를 사용하면 됩니다.
case class Book(title: String, body: String)
// 전체 일치 비교
Book("title", "body") shouldBe Book("title", "body")
// 일부 일치 비교
// have 함수 내부에 비교 필드를 '를 앞에 적고 비교하면 됩니다
Book("title", "body") should have {
'title ("title")
'body ("body")
}
Custom be matchers
단순한 equality 비교 이외에도 사용자가 직접 be 함수에 연동해서 사용할 수 있는 be matchers를 만들 수 있습니다.
be matchers를 만들고싶다면 BeMatchers[T]를 상속받아서 만들면 됩니다.
import org.scalatest.matchers.should.Matchers.not
import org.scalatest.matchers.{BeMatcher, MatchResult}
trait MyMatchers {
class OddMatcher extends BeMatcher[Int] {
def apply(left: Int) =
MatchResult(
left % 2 == 1,
left.toString + " was even",
left.toString + " was odd"
)
}
val odd = new OddMatcher
val even = not (odd)
}
// 필요하다면 trait를 상속받지 않고 직접 import해서 사용해도 됩니다
// import CustomMatchers._
object CustomMatchers extends CustomMatchers
// 다음처럼 사용하면 됩니다
val evenNum = 2
evenNum should be (even)
evenNum should be (odd)
ScalaTest는 이외에도 다양한 matcher 함수들을 제공해주니 필요하다면 document를 참조해서 사용하면 됩니다.