用于'的最新自定义匹配器应包含'

时间:2016-01-14 13:17:42

标签: scala scalatest

这是我经常遇到的情况,但我还没有找到解决方案。

假设您有一个人员列表,并且您只想验证人名。 这有效:

persons.map(_.name) should contain theSameElementsAs(List("A","B"))

相反,我宁愿写这个像

val toName: Person => String = _.name
persons should contain theSameElementsAs(List("A","B")) (after mapping toName)

因为你会这么说。

但有时候,您希望使用自定义匹配器,它不仅仅匹配对象的一个​​属性。如何使用

persons should contain(..)

语法,但不知何故能够使用自定义匹配器?

我可以使用Hamcrest匹配器使用JUnit或TestNG轻松解决这两种情况,但我还没有找到使用ScalaTest执行此操作的方法。

我试图在'之后使用'来自显式特征的语法,但这是不可能的,因为这需要'规范化'它定义了'标准化' method对参数和返回类型使用相同的类型。因此无法将Person更改为String。 此外,我还没有成功地实施一个明确的'喜欢trait因为它不喜欢我返回的Equality [。]类型和/或它不知道原始列表类型是什么,所以使用' _。name'不编译。

欢迎任何建议。

1 个答案:

答案 0 :(得分:2)

您可以通过单词decided管理类似内容并轻度滥用Equality特征。这是因为Equality特征的areEqual方法采用了泛型类型的参数和Any类型的参数,因此您可以使用它来比较Person Stringdecided by仅使用Equality对象,这意味着您不必使用Normality

import org.scalactic.Equality
import org.scalatest.{FreeSpec, Matchers}

final class Test extends FreeSpec with Matchers {

  case class Person(name: String)

  val people = List(Person("Alice"), Person("Eve"))

  val namesBeingEqual = MappingEquality[Person, String](p => p.name)

  "test should pass" in {
    (people should contain theSameElementsAs List("Alice", "Eve"))(
      decided by namesBeingEqual)
  }

  "test should fail" in {
    (people should contain theSameElementsAs List("Alice", "Bob"))(
      decided by namesBeingEqual)
  }

  case class MappingEquality[S, T](map: S => T) extends Equality[S] {

    override def areEqual(s: S, b: Any): Boolean = b match {
      case t: T => map(s) == t
      case _    => false
    }
  }
}

我不确定我是否认为这是一个好主意,因为它并没有像人们期望任何名为Equality的行为那样表现,但它确实有效。

您甚至可以通过隐式转换将beingMapped语法添加到after来获得您建议的 implicit class AfterExtensions(aft: TheAfterWord) { def beingMapped[S, T](map: S => T): Equality[S] = MappingEquality(map) } } 语法:

after

我确实尝试通过Uniformity特征使Any使用Uniformity[String]特征,该特征具有涉及Uniformity[Person]的类似方法,但遇到了问题,因为规范化是错误的方法:我可以从您的示例中创建normalized对象,但不是Equality对象。 (原因是' sa "test should succeed" in { val mappedToName = MappingUniformity[Person, String](person => person.name) (List("Alice", "Eve") should contain theSameElementsAs people)( after being mappedToName) } case class MappingUniformity[S, T](map: S => T) extends Uniformity[T] { override def normalizedOrSame(b: Any): Any = b match { case s: S => map(s) case t: T => t } override def normalizedCanHandle(b: Any): Boolean = b.isInstanceOf[S] || b.isInstanceOf[T] override def normalized(s: T): T = s } 方法返回用于构造{CUSTOM FIELD LABEL}: {CUSTOM FIELD VALUE} 对象的泛型类型,这意味着为了将字符串与字符串进行比较,左侧输入必须是string。)这意味着写它的唯一方法是使用与正常情况相反的预期vs实际值:

__()

绝对不是你通常想写的。