ScalaTest——matcher匹配器

xiaoxiao2022-06-11  32

ScalaTest中的Matchers匹配器分为两大类:Should Matcher和Must Matcher。

它们的区别仅在测试报告中体现,所以在后面不同情形下的Matcher的说明中,只以Should Matcher为例。

3.1 简单匹配器

Simple Matcher就是在两个值之间使用一个断言

在测试代码里,我们作出了一个断言:Thriller这张专辑的作者的firstName是Michael。可以看到代码有一个should,这就是ScalaTest中的两大类Matcher之一的Should Matcher (另一类是Must Matcher,用must来表示) import org.scalatest.{FunSpec, Matchers} class Artist(val firstName:String,val lastName:String) class Album(val title:String,val year:Int,val artist:Artist) class AlbumTest extends FunSpec with Matchers { describe("An Album") { it("can add an Artist object to the album") { val album = new Album("Thriller", 1981, new Artist("Michael", "Jackson")) album.artist.firstName should be("Michael") } } } ------------------------------------------------------------------- class AlbumTest1 extends FunSuite with Matchers{ test("album test"){ val album = new Album("Thriller",1981,new Artist("Michael","Jackson")) album.artist.firstName should be ("Michael") //assert(album.artist.firstName == "michael") } } ------------------------------------------------------------------- class simpleMacher extends FunSpec with Matchers{ describe("test"){ it("listSize"){ val list = 2::4::5::Nil list.size should be(3) // assert(list.size==3) } } }

这里有几点需要注意:

1.右边的值需要使用圆括号()括起来 list.size should be 3 // 这种写法会导致编译错误 2.可以将be替换为equal list.size should equal(3) // 这种写法和 list.size should be(3) 等价 3.在ScalaTest中基本不使用 == 和 != 进行条件断言 如果上面的代码写成:list.size == 5 这样写只会验证list.size == 5这是表达式是true或者false,并不会进行断言的验证 因而不会有TestFailedException异常抛出,测试将继续运行。
3.2 字符串匹配器

String Macher为字符串断言提供了一些有用的方法,利用这些方法可以判断一个字符串是否包含另一个字符串、一个字符串以某个字符串开头或结尾、一个字符串是否能匹配一个正则表达式等。如下面的例子:

val string = """I fell into a burning ring of fire.I went down, down, down and the flames went higher""" string should startWith("I fell") // 以 "I fell" 字符串开头 string should endWith("higher") // 以 "higher" 字符串结尾 string should not endWith " the end" // 不以 "the end" 字符串结尾 string should include("down, down, down") // 包含 "down, down, down" 字符串 string should not include ("Great balls") // 不包含 "Great balls" 字符串 string should startWith regex ("I.fel+") // 以匹配正则表达式 "I.fel+" 的字符串开头 string should endWith regex ("h.{4}r") // 以匹配正则表达式 "h.{4}r" 的字符串结尾 string should not endWith regex("\\d{5}") // 不以匹配正则表达式 "\\d{5}" 的字符串结尾 string should include regex ("flames?") // 包含匹配正则表达式 "flames?" 的字符串 string should fullyMatch regex ("""I(.|\n|\S)*higher""") // 完全匹配正则表达式 "I(.|\n|\S)*higher"
3.3 关系操作匹配器

ScalaTest框架支持关系运算符,如下面的例子

val answerToLife = 42 answerToLife should be < (50) answerToLife should not be > (50) answerToLife should be > (3) answerToLife should be <= (100) answerToLife should be >= (0) answerToLife should be === (42) //===运算符用于检验左边是否等于右边。 answerToLife should not be === (400) //而==只是验证值是否相等并不会验证断言 因此在涉及验证是否相等时最好使用 should be 或 should equal 或 ===。
3.4 误差范围匹配器

浮点数在JVM中实际上是很复杂的,考虑一个算式0.9 - 0.8,在我们看来结果应该是0.1,实际上在REPL中执行这个运算,会得到如下的结果:

scala> 0.9 - 0.8 res0: Double = 0.09999999999999998 显然计算结果是有误差的。在ScalaTest框架中提供一个+-方法来给断言提供一个误差允许范围。如下面的例子: // 允许右边的范围在 0.1 - 0.01 到 0.1 + 0.01 之间 (0.9 - 0.8) should be (0.1 +- 0.01) // 允许右边的范围在 40 - 0.3 到 40 + 0.3 之间 (0.4 + 0.1) should not be (40.00 +- 0.30) //在REPL中会输出一个准确值 0.5
3.5 引用匹配器

在Scala中==运算符不会验证引用是否相等

要验证引用是否相等,在ScalaTest中提供了theSameInstanceAs方法,如下面的例子:

class Artist(val firstName:String,val lastName:String) val garthBrooks = new Artist("Garth", "Brooks") val chrisGaines = garthBrooks garthBrooks should be theSameInstanceAs (chrisGaines) val debbieHarry = new Artist("Debbie", "Harry") garthBrooks should not be theSameInstanceAs(debbieHarry)
3.6 Iterable匹配器

对于Scala的可遍历集合类型,ScalaTest框架提供了多种进行断言的方法。如下面的例子:

List() should be('empty) //'empty,Scala中的符号是不可变的占位符。 8::6::7::5::3::0::9::Nil should contain(7)
3.6 Seq和traversable匹配器

对于Seq和Traversable类型的Scala变量,SalaTest提供了length和size这两个Matcher来判定它们的大小(长度)。如下面的例子:

(1 to 9) should have length (9) (20 to 60 by 2) should have size (21) 实际上根据Scala文档,length和size是等价的,使用哪个完全看你的偏好。
3.7 Map匹配器

而对于Map类型的Scala变量,ScalaTest提供了一些特殊的方法,可以用来判断一个key或者value是否在Map中。如下面的例子:

val map = Map("Jimmy Page" -> "Led Zeppelin", "Sting" -> "The Police", "Aimee Mann" -> "Til\' Tuesday") map should contain key ("Sting") // map中应该包含值为 "Sting" 的key map should contain value ("Led Zeppelin") // map中应该包含值为 "Led Zeppelin" 的value map should not contain key("Brian May") // map中应该不包含值为 "Brian May" 的key
3.8 复合操作匹配器

ScalaTest中的and和or方法可以用来在测试中使用组合的断言。如下面的例子:

val hot = List("Anthony Kiedis", "Flea", "Chad Smith", "Josh Klinghoffer") // hot变量中应该包含 "Anthony Kiedis" 不应该包含 "John Frusciante" 和 "Dave Navarro" hot should (contain("Anthony Kiedis") and (not contain ("John Frusciante") or contain("Dave Navarro"))) 在使用组合的Macher时,圆括号()的使用可能会造成一此困扰,下面是一些规则: 1. and和or的断言必须使用圆括号()包围起来 2. 断言的右边必须使用圆括号()包围起来 以下面的例子来说明上面两条规则: // 这会导致编译错误 hot should not contain "The Edge" or contain "Kenny G" // 这也会导致编译错误 hot should not (contain "The Edge" or contain "Kenny G") // 这是正确的写法 hot should not (contain ("The Edge") or contain ("Kenny G"))

除了上面的两条规则,还有一点需要注意的:使用组合and或or并不是短路的。换句话说,就是所有的子句都会被验证。如下面的例子:

var total = 3 hot should not (contain ("The Edge") or contain {total += 6; "Kenny G"}) total should be (9) 如果发生短路,total should be (9)这里肯定不能通过 not contain ("The Edge")已经是true,则or运算没必要再运行。 但执行完这个测试发现total的值已经是9,说明此时并没有发生短路。

Scala中有一个Option类型,其值可以为Some或None,因此,在Scala中基本不会使用null来做处理。ScalaTest是支持Java的,因此在有些情况下需要用到null。如下面的例子:

gorillaz should (not be (null) and contain ("Damon Albarn")) 如果gorillaz为null则会抛出NullPointerException异常。更好的最法是将组合Matcher拆开: gorillaz should not be (null) gorillaz should contain ("Damon Albarn") 经过上面的处理如果gorillaz为null,测试不会通过,但其它的测试不会抛出NullPointerException异常。
3.9 属性匹配器

ScalaTest也提供了一个很不错的方式来验证对象的属性,如下面的例子:

import scala.collection.mutable.WrappedArray class Artist(val firstName:String,val lastName:String) class Album(val title:String,val year:Int,val artist:Artist) val album = new Album("Blizzard of Ozz", 1980, new Artist("Ozzy", "Osbourne")) album should have ( 'title ("Blizzard of Ozz"), 'year (1980), 'artist (new Artist("Ozzy", "Osbourne")) //写法有误 ) 属性Macher可以将对象的属性取出来,然后对这些属性进行断言。这里将属性取出来实际上是使用了对象的getter方法,所以需要保证在对象中有getter方法并且能调用到。
3.10 java.util.Collection匹配器

ScalaTest是Java友好的,因而它可以像在Scala集合上一样在Java集合上做断言,下面的例子使用了一些在之前用到的方法。ScalaTest在Java集合上的操作和在Scala集合上的操作是一样的。

import java.util.{List => JList, ArrayList => JArrayList, Map => JMap, HashMap => JHashMap} val jList: JList[Int] = new JArrayList[Int](20) jList.add(3); jList.add(6); jList.add(9) val emptyJList: JList[Int] = new JArrayList[Int]() emptyJList should be('empty) jList should have length (3) jList should have size (3) jList should contain(6) jList should not contain (10) val backupBands: JMap[String, String] = new JHashMap() backupBands.put("Joan Jett", "Blackhearts") backupBands.put("Tom Petty", "Heartbreakers") backupBands should contain key ("Joan Jett") backupBands should contain value ("Heartbreakers") backupBands should not contain key("John Lydon")
3.11 Must匹配器

在前面的一些例子中,都是使用Should Macher的should这个关键字,实际上可以把前面的should都换成must,这完全是等价的。正如之前说过的,Should Macher和Must Macher的不同之处只在测试报告中体现。

val list = 2 :: 4 :: 5 :: Nil list.size must be(3) val string = """I fell into a burning ring of fire. I went down, down, down and the flames went higher""" string must startWith regex ("I.fel+") string must endWith regex ("h.{4}r") val answerToLife = 42 answerToLife must be < (50) answerToLife must not be >(50) val garthBrooks = new Artist("Garth", "Brooks") val chrisGaines = garthBrooks val debbieHarry = new Artist("Debbie", "Harry") garthBrooks must be theSameInstanceAs (chrisGaines) (0.9 - 0.8) must be(0.1 plusOrMinus .01) List() must be('empty) 1 :: 2 :: 3 :: Nil must contain(3) (1 to 9).toList must have length (9) (20 to 60 by 2).toList must have size (21) val map = Map("Jimmy Page" -> "Led Zeppelin", "Sting" -> "The Police", "Aimee Mann" -> "Til\' Tuesday") map must contain key ("Sting") map must contain value ("Led Zeppelin") map must not contain key("Brian May") val redHotChiliPeppers = List("Anthony Kiedis", "Flea", "Chad Smith", "Josh Klinghoffer") redHotChiliPeppers must (contain("Anthony Kiedis") and (not contain ("John Frusciante") or contain("Dave Navarro")))
转载请注明原文地址: https://www.6miu.com/read-4930173.html

最新回复(0)