Async test
Scala 코드를 작성하면 기본적으로 sync-blocking 방식의 코드가 아닌 async-non-blocking 방식의 코드를 작성하게 됩니다. async, non-blocking 방식의 코드는 기본적으로 테스트하기 복잡하지만, ScalaTest는 이를 위한 테스트 방식을 제공해주고 있습니다.
기존의 테스트 스타일에 async 키워드를 붙여주면 async, non-blocking 방식의 테스트가 가능해집니다.
지원해주는 테스트 스타일들은 아래와 같습니다.
- AsyncFunSuite
- AsyncFlatSpec
- AsyncFunSpec
- AsyncWordSpec
- AsyncFreeSpec
- AsyncFeatureSpec
PropSpec과 RefSpec에 대응되는 Async 스펙은 지원하지 않습니다.
Blocking Assertion (비추천)
위에 적은 AsyncXXSpec을 사용하지 않고도 Future 테스트를 검증할 수 있습니다.
검증할 코드의 결과값을 Await로 blocking하여 최종 결과가 나올 때까지 대기하면 됩니다.
단점은 테스트가 그대로 blocking 상태에 들어가 테스트 수행 시간이 상당히 느리다는 점입니다.
테스트가 그렇게 많지 않다면 사용할만한 방법이지만 장기적으로는 추천하지 않습니다.
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext, Future}
class AddSpec extends AnyFlatSpec with Matchers {
implicit val ec = ExecutionContext.global
def futureSum(nums: Int*): Future[Int] = Future { nums.sum }
"Future 덧셈" should "최종적으로 덧셈 결과를 반환한다" in {
// given
val nums = Array(1, 2, 3)
// when
val actual = Await.result(futureSum(nums: _*), Duration.Inf)
// then
actual shouldBe 6
}
}
Future Assertion (추천)
ScalaTest의 AsyncXXSpec trait를 상속받으면 Future[Assertion] 형태의 Assertion을 지원해줍니다.
Future의 결과로 map을 연결하고, 해당 map에서 assertion을 작성하면 ScalaTest가 테스트로 인식하고 테스트의 결과를 검증해줍니다.
AsyncXXSpec을 사용한다고 해서 반드시 Future 형태의 결과를 검증할 필요는 없고 기존의 sync-blocking 테스트도 검증할 수 있습니다.
import org.scalatest.flatspec.AsyncFlatSpec
import org.scalatest.matchers.should.Matchers
import scala.concurrent.Future
class AddSpec extends AsyncFlatSpec with Matchers {
def futureSum(nums: Int*): Future[Int] = Future { nums.sum }
"Future 덧셈" should "최종적으로 덧셈 결과를 반환한다" in {
// given
val nums = Array(1, 2, 3)
// when
val actual = futureSum(nums: _*)
// then
actual map { res => res shouldBe 6 }
}
def nowSum(nums: Int*): Int = nums.sum
"기본 덧셈" should "Future가 아니어도 성공시킬 수 있다" in {
// given
val nums = Array(1, 2, 3)
// when
val actual = nowSum(nums: _*)
// then
actual shouldBe 6
}
"succeed" should "강제로 테스트를 성공시킬 수 있다" in {
println("문자열 출력")
succeed
}
}