ScalaTest——matcher匹配器

ScalaTest中的Matchers匹配器分为两大类:Should MatcherMust 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匹配器

对于SeqTraversable类型的Scala变量,SalaTest提供了lengthsize这两个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中的andor方法可以用来在测试中使用组合的断言。如下面的例子:

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 Machershould这个关键字,实际上可以把前面的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")))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值