如何在Scala测试中检查“Either”结果?

9

我对Scala Test比较陌生,所以我查阅了文档来学习如何测试Either值。

我按照指示进行了复制,就像这样:

import org.scalatest.EitherValues
import org.scalatest.flatspec.AnyFlatSpec

class EitherTest extends AnyFlatSpec with EitherValues {
  val either: Either[Exception, Int] = Right(42)

  either.right.value should be > 1
}

这种实现方式行不通,我遇到了语法错误。我做错了什么?

错误:

错误:(9,22)value不是Int的成员,either.right.value应该是>1

错误:(9,29)未找到:value,either.right.value应该是>1 - Hannes 14小时前


1
你得到了什么错误?你能把它加上吗? - sinanspd
Error:(9, 22) value should is not a member of Int either.right.value should be > 1 Error:(9, 29) not found: value be either.right.value should be > 1 - Hannes
你能否尝试从Either中删除显式类型签名,看看是否可以正常工作?val either = Right(42) - sinanspd
5
@Hannes:我认为你漏掉了混入Matchers的代码(例如class EitherTest extends AnyFlatSpec with EitherValues with Matchers)。 - Marth
是的,Either.right已被弃用,因为它是右导向的。either.contains或either.exists应该适合您的需求。 - Salim
显示剩余2条评论
4个回答

6

通过与模式匹配来进行测试可以更易读。ScalaTest的 Inside 特质允许您在模式匹配后进行断言。

import org.scalatest.Inside
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class EitherTest extends AnyFlatSpec with Inside with Matchers {
  val either: Either[Exception, Int] = Right(42)

  either should matchPattern { case Right(42) => }

  inside(either) { case Right(n) =>
    n should be > 1
  }

  val either2: Either[Exception, Int] = Left(new Exception("Bad argument"))

  inside(either2) { case Left(e) =>
    e.getMessage should startWith ("Bad")
  }

}

谢谢你提供这段代码,我会试一下!但是我有两个问题:1)那个 => } 语法是什么?我知道匹配语法,但我不知道你可以省略表达式的右侧部分。2)matchPattern 能否和 "Either" should matchPattern in { ...} 语法一起使用? - Hannes
@Hannes 1. 右侧部分是一个没有任何实现的空单元。我们只检查是否与模式匹配。 2. 在 Scalatest 文档中了解有关匹配模式的更多详细信息:http://www.scalatest.org/user_guide/using_matchers#matchingAPattern - Yuriy Tumakha

5
有一个未决的 pull request,添加 EitherValuable #1712,旨在解决 Scala 2.13 中 RightProjection废弃的事实:

目前.right被废弃了(我相信它会一直保持这个状态),但是.left不是,正如scala/scala#8012所示。

未来的 ScalaTest 版本中,EitherValues 的新语法可能会变为 rightValueleftValue
either.rightValue should be > 1

4
这是我会做的方式。

首先检查是否正确,然后比较值:

either.isRight shouldBe true
either.getOrElse(0) shouldBe 42

另一种方式是在不正确的情况下失败:

either.getOrElse(fail("either was not Right!")) shouldBe 42

我建议你使用类似于WordSpec的测试框架来包装你的测试代码:

"My Either" should {
  "be Right" in {
    either.getOrElse(fail("either was not Right!")) shouldBe 42
  }
}

这将提示您问题出现的位置。否则,如果失败,您将只得到一个糟糕的错误堆栈。

以下是一个完整的示例:

class EitherTest
  extends WordSpec
  with Matchers
  with EitherValues {

  // val either: Either[Exception, Int] = Right(42)
  val either: Either[Exception, Int] = Left(new IllegalArgumentException)
  "My Either" should {
    "be Right" in {
      either.getOrElse(fail("either was not Right!")) shouldBe 42
    }
  }
}

shouldBe 似乎不存在。我需要另一个混入(mix-in)吗? - Hannes
我认为你错过了 with Matchers,请看我的更新答案。 - pme

0
你考虑过使用inside特质吗?这样你就可以使用模式匹配来测试Either中的值。例如:
import org.scalatest.Inside.inside
...
val result = FooBarInputValidator(value)
inside(result) { case Left(validationError) => 
   validationError.message shouldBe "Invalid input"
   validationError.parameter shouldBe "FooBar"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接