ScalaMock- 提升用例完整度利器

相信每個軟件從業(yè)者都意識到測試在項目中重要性栓袖∶蛊欤“愛恨交織”足以形容我們和測試用例關系。愛它為我們發(fā)現的巨坑,恨它則因為絞盡腦汁構建測試場景棺妓。

毋庸置疑的是:測試用例是項目管理不可或缺部分。為了更好的服務項目鲤遥,豐富而完整的測試用例是必要的斋日。

在編寫測試用例時,函數中調用的其它函數挠羔,或者引用外部資源井仰。在不使用資源的情況下,我們想做到更好的測試破加,需要模擬外部函數的結果俱恶。今天的主角ScalaMock是便于我們模擬外部結果測試組件。

ScalaMock介紹

ScalaMock和JUnit, NUnit*測試框架不同,它沒有提供底層的測試代碼合是,而是基于兩種測試框架之上(ScalaTest和Specs2)了罪。它類似于給測試框架提供構建“假”的代碼運行環(huán)境或者叫“樁”。為編寫測試用例提供便捷語法糖聪全,很甜很甜那種泊藕,哈哈。本文通過使用scalamock構造簡單的測試場景难礼,來展現其功能娃圆。

用例運行環(huán)境

一切沒有預置前提的說明文檔都必然是耍流氓,_

// Add the ScalaMock library (versions 4.0.0 onwards)
libraryDependencies += "org.scalamock" %% "scalamock" % "4.4.0" % Test
// also add ScalaTest as a framework to run the tests
//scala test inter scala mock sugar
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % Test</pre>

本文用例基于 scalmock 4.4.0scalatest 3.0.8的版本蛾茉。

ScalaMock的是與非

ScalaMock 運行基于 scalatest讼呢,我們編寫的用例形式上要遵循scalatest的形式。從以下3個方面介紹scalamock.

  • 匿名函數mock
  • trait mock
  • class mock
    在介紹使用場景前谦炬,先看看scalamock語法樣式吝岭。
  • ScalaMock語法樣式

//匿名函數格式: mockFunction,入參 string吧寺,int , 返回值String
val funcMock = mockFunction[String, Int, String]
// 格式 變量 expects()關鍵字+ returning關鍵字 + 返回值("wayne mock") + 附加屬性(once()只執(zhí)行一次)
funcMock expects("hello world", 18) returning "wayne mock" once() //once
//樣式含義是:當輸入期望特定的輸入時窜管,返回returning 值。

基于函數的Mock

函數mock關鍵字是:mockFunction.

  • 匿名函數mock

//定義函數mock
val funcMock = mockFunction[String, Int, String]
funcMock expects("hello world", 18) returning "function mock" atLeastOnce() //call at least once
?
//調用
println(funcMock("hello world", 18)) //輸出: function mock </pre>

atLeastOnce() 使用scalamock 時稚机,設置屬性表示mock的內容被調用的次數幕帆。

匿名函數mock使用頻率不高,更多使用trait class方式進行mock赖条。下文有匿名函數進行mock的使用場景失乾。

基于trait 的mock

trait進行mock操作關鍵字是:mock.

源碼如下:

trait MyMockTest {
def funcOnePara(name: String): String = { //一個參數
name
}
?
def funcTwoPara(name: String, age:Int): String = name //2個參數
def funcNoArgs: String = "func no args" //無參數函數
val valPara="variable param"
}

  • mock trait 示例

    • mock trait無參數示例

val my = mock[MyMockTest]

(my.funcNoArgs _ ).expects().returning("no args") //mock funcNoArgs返回no args
?
my.funcNoArgs shouldBe("no args")//scala test 結果比較

定義了my變量之后,就可以對trait內所有的函數進行mock操作了纬乍。其它沒有mock的函數不影響碱茁。

trait TraitExtend extends MyMockTest
val my = mock[TraitExtend]
println(my.funNoArgs) //輸出func no args

  • trait有參調用mock

trait 有參數mock編寫方式有兩種,僅僅是寫法上差異仿贬,本質上沒有差別

  1. 根據參數類型進行mock

//使用指定 參數類型的方式纽竣,mock 有參函數
(my.funcOnePara(_:String)).expects("wayne") returning("one para")
println(my.funcOnePara("wayne"))

  1. 根據匿名函數,使用類型推導方式 mock

//使用指定 匿名函數的方式茧泪,利用依賴函數推導蜓氨,mock 有參函數
(my.funcOnePara _ :String => String).expects("wayne") returning("one para")
println(my.funcOnePara("wayne"))

  • val/var變量不支持mock

我們無法在外部使用其它val變量時,模擬偽裝其結果队伟。 只能通過其它方式穴吹,見后文。

基于class 的mock

編寫測試用例時嗜侮,我們遇見更多場景是函數中調用其它類函數港令,或者引用外部資源啥容。在不使用資源的情況下,做到更好的測試顷霹,我們需要對外部函數進行mock操作咪惠。基于class進行mock是更普適使用場景泼返。

class 進行mock操作關鍵字是:mock.

//源碼示例

class MyMockClass {
var age: Int = 0
def funcMock = ""
?
}

class的構成和trait構成類似,因此mock的方式也是一致的姨拥。類中函數模擬示例绅喉,和trait沒有任何區(qū)別。

//mock class without param
val t = mock[MyMockClass]
(t.funcMock _ ) expects() returning("mock class function")
?
println(t.funcMock)

值得關注的是:不論mock那種類型叫乌,都是對該類型進行操作柴罐。只影響指定輸入和返回值的函數,對其它沒有影響

基于case class 的mock

樣例類在scala中是特殊的存在憨奸,即作為數據的承載者革屠,有具備處理能力。我們采用投機的版本進行mock,你們函數的mock排宰。定義樣例類Person進行mock測試似芝。示例如下:

case class Person(age:Int, address:String)
//case class mock 一個變量或者函數 沒有mock必要
val caseMock = mockFunction[Unit,Person]
(caseMock).expects().returning(Person(age= 12))
?
println(caseMock().age)

我們看到給Personmock的方法是采用我們上文提到的匿名函數。

ScalaMock其它支持特性
  • 支持重載方法的重載

  • 支持java的類和接口

  • 支持邊界測試板甘,即給出邊界值党瓮,拋出異常

  • 支持統(tǒng)計函數調用次數,和函數調用次數類似

  • 支持對返回值類型排序

  • 支持在多線程環(huán)境進行mock

ScalaMock 力所不及

如果看到scalaMock的實現原理盐类,我們會發(fā)現我們常用的 單例對象寞奸、有參數class都不能進行mock操作。

下面列舉下scalamock不支持的特征

  • 不支持 final/private等關鍵字mock

  • 不支持單例object對象 mock

    注:一個可支持mock的方法是:把單例對象修改成trait對象在跳,或者把調用單例對象封裝到實現調用類中枪萄,通過mock方法形式達到mock 單例對象的目的,曲線“救國”吧猫妙。

以上敘述scalamock用法瓷翻,由于其內在的約束,要想用好scalamock割坠,既要了解用法逻悠,更重要的是編碼的合理性。工具有優(yōu)越性建立在優(yōu)秀的代碼之上韭脊。

下一篇童谒,介紹scala的其它mock組件。

據說點贊沪羔、評論 減少100%bug饥伊。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末象浑,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子琅豆,更是在濱河造成了極大的恐慌愉豺,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茫因,死亡現場離奇詭異蚪拦,居然都是意外死亡,警方通過查閱死者的電腦和手機冻押,發(fā)現死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門驰贷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人洛巢,你說我怎么就攤上這事括袒。” “怎么了稿茉?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵锹锰,是天一觀的道長。 經常有香客問我漓库,道長恃慧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任渺蒿,我火速辦了婚禮糕伐,結果婚禮上,老公的妹妹穿的比我還像新娘蘸嘶。我一直安慰自己良瞧,他們只是感情好,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布训唱。 她就那樣靜靜地躺著褥蚯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪况增。 梳的紋絲不亂的頭發(fā)上赞庶,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天,我揣著相機與錄音澳骤,去河邊找鬼歧强。 笑死,一個胖子當著我的面吹牛为肮,可吹牛的內容都是我干的摊册。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼颊艳,長吁一口氣:“原來是場噩夢啊……” “哼茅特!你這毒婦竟也來了忘分?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤白修,失蹤者是張志新(化名)和其女友劉穎妒峦,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體兵睛,經...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡肯骇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了祖很。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笛丙。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖突琳,靈堂內的尸體忽然破棺而出若债,到底是詐尸還是另有隱情符相,我是刑警寧澤拆融,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站啊终,受9級特大地震影響镜豹,放射性物質發(fā)生泄漏。R本人自食惡果不足惜蓝牲,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一趟脂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧例衍,春花似錦昔期、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至梦抢,卻和暖如春般贼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奥吩。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工哼蛆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人霞赫。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓腮介,卻偏偏與公主長得像,于是被迫代替她去往敵國和親端衰。 傳聞我的和親對象是個殘疾皇子萤厅,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359