Search code examples
scalaunit-testingscalatest

How to test a Try[T] in ScalaTest correctly?


I've checked the answers specified in the post How to test a Try[T] with ScalaTest correctly?

But if I had to do any assertions after the function call or if I have to check the assertions within a for { } yield { } block then I'm following the below given approach:

  def test(a: Int, b: Int): Try[Int] = Try {
    a / b
  }

  it.should("succeed").in {
    (for {
      res <- test(0, 1)
    } yield {
      assert(res === 0)
      // assume more assertions are to be made
    }) match {
      case Success(value)     => value
      case Failure(exception) => fail(exception)
    }
  }

  it.should("fail").in {
    test(1, 0).failure.exception.getClass.mustBe(classOf[java.lang.ArithmeticException])
  }

The problem with above approach is that, for the success case if any issue happens in the unit test logic then it'll show the error pointing to the line case Failure(exception) => fail(exception) and not on the line where the actual error occurred. If the test case is huge then it'll be difficult for the user to find where exactly the error occurred.

So is there a better way to unit test the functions which returns a Try[T] without moving the assertions outside the for { } yield { } block?


Solution

  • The TryValues trait (documented here) is designed to help with this:

    class MyTestSpec extends FlatSpec with Matchers with TryValues {
      "tryTest" should "succeed" in {
        // Normal tests
        test(0, 1).isSuccess shouldBe true
        test(1, 1).isFailure shouldBe true
    
        // Use TryValues conversions
        test(0, 1).success.value shouldBe 0
        test(1, 1).failure.exception should have message "should be zero"
      }
    }