编码的喜悦……以及Java中的变异测试
多年以來(lái),為源代碼編寫(xiě)單元測(cè)試一直是一種好習(xí)慣。 并且還可以使用測(cè)試覆蓋率報(bào)告來(lái)查看測(cè)試覆蓋了多少代碼。 盡管行+分支覆蓋率報(bào)告非常有用,但是它并不能告訴您單元測(cè)試的實(shí)際效果。 因此,甚至在測(cè)試中沒(méi)有一個(gè)斷言的情況下,甚至有可能達(dá)到100%的覆蓋率。
對(duì)更好的測(cè)試方法感興趣,我參加了今年的“ 歡樂(lè)編碼 ”會(huì)議期間的“突變測(cè)試”研討會(huì)。
變異測(cè)試是執(zhí)行和分析單元測(cè)試的結(jié)果及覆蓋范圍的一種截然不同的方法。 無(wú)需衡量單元測(cè)試“訪問(wèn)了”多少代碼,而是確定單元測(cè)試實(shí)際上“測(cè)試了”多少代碼。
那么它實(shí)際上是如何工作的
變異測(cè)試背后的基本思想是對(duì)(字節(jié))代碼進(jìn)行小改動(dòng)(變異),然后執(zhí)行測(cè)試以查看是否被單元測(cè)試檢測(cè)到。
可能的突變是將“ > ”更改為“ >= ”,將“ ++ ”替換為“ -- ”,并刪除“ void ”方法調(diào)用。
因此,每個(gè)突變都會(huì)創(chuàng)建代碼的變更版本,稱為“突變”。
在進(jìn)行實(shí)際的變異測(cè)試之前,首先需要針對(duì)原始代碼執(zhí)行單元測(cè)試,以查看是否沒(méi)有測(cè)試失敗。
然后,將對(duì)每個(gè)“突變體”運(yùn)行單元測(cè)試(這可能非常耗時(shí)),看是否:
- 我們的單元測(cè)試檢測(cè)到該突變體:測(cè)試失敗,因此“突變體”被視為“已殺死”。
- 在我們的單元測(cè)試中,突變體仍然未被注意到:測(cè)試沒(méi)有“沒(méi)有”失敗(“突變體”被認(rèn)為是“存活”)并且沒(méi)有注意到突變; 這意味著單元測(cè)試實(shí)際上是“未”測(cè)試(未發(fā)現(xiàn))“突變體”的。
變異測(cè)試的一個(gè)例子
那么,這種“變異測(cè)試”實(shí)際上是如何工作的呢?
請(qǐng)考慮以下方法:
單元測(cè)試僅包含一種測(cè)試方法:
@Test public void testFoo() {testee.foo(0); } 如果我們要?jiǎng)?chuàng)建代碼的“突變體”,將“ >= ”更改為“ > ”,該怎么辦?
我們希望我們的單元測(cè)試方法能夠檢測(cè)到這一點(diǎn),對(duì)吧? 好吧,在這種情況下不是因?yàn)闇y(cè)試方法不包含單個(gè)斷言。
我們將更改一個(gè)“ testFoo”方法以包含一個(gè)斷言:
@Test public void testFoo() {String result = testee.foo(0);assertEquals("foo", result); }現(xiàn)在,我們的單元測(cè)試方法將失敗并檢測(cè)(也稱為“殺死”)“突變”代碼。
除了將“ >= ”更改為“ > ”以外,還可以創(chuàng)建其他“突變體”:
- 可以將第一個(gè)return方法更改為返回null (而不是"foo" );
由于使用“ assertEquals”語(yǔ)句,此“突變體”被“ testFoo”方法“殺死”,但仍未被注意到原始的“ testFoo”方法(沒(méi)有任何斷言)。 - 可以將第二個(gè)return方法更改為返回null (而不是"bar" );
由于沒(méi)有測(cè)試方法實(shí)際覆蓋此執(zhí)行路徑,因此該“突變”將不會(huì)被注意到。
注意 :一些變異測(cè)試工具(例如Java的PIT)甚至不會(huì)費(fèi)心為第二個(gè)return語(yǔ)句創(chuàng)建“變異”,因?yàn)樗粫?huì)被單元測(cè)試所覆蓋(如傳統(tǒng)的行覆蓋率所檢測(cè))。
等效突變導(dǎo)致假陽(yáng)性
與傳統(tǒng)的行+分支覆蓋相比,突變覆蓋可能會(huì)導(dǎo)致假陽(yáng)性。
它可能“錯(cuò)誤地”報(bào)告(假陽(yáng)性)單元測(cè)試未檢測(cè)到“突變”為“未”。
例如,考慮以下Java代碼:
public int someNonVoidMethod() { return 0; } public void foo() {int i = someNonVoidMethod();// do more stuff with i }在變異測(cè)試期間(使用具有某些“非”默認(rèn)配置的PIT變異測(cè)試),可能會(huì)創(chuàng)建以下“變異”:
public int someNonVoidMethod() { return 0; } public void foo() {int i = 0;// do more stuff with i } “ mutant”中的“ int i = 0 ”語(yǔ)句在功能上與“ someNonVoidMethod ”返回0的原始代碼“等效”。
由于單元測(cè)試不會(huì)(也不應(yīng))失敗,因此無(wú)法檢測(cè)到這種“等效突變”。
因此,它將被報(bào)告為未覆蓋,而實(shí)際上它是一個(gè)假陽(yáng)性。
根據(jù)文檔 ,在使用PIT(一種用于Java的突變測(cè)試框架)時(shí),“等效突變”應(yīng)使用“默認(rèn)”的一組突變體最小化。
例如,默認(rèn)情況下會(huì)禁用導(dǎo)致“ int i = 0 ”等效突變的PIT的“非無(wú)效方法調(diào)用突變器”。
結(jié)論
在參加了研討會(huì),一些額外的調(diào)查并與PIT合作之后,我非常熱衷于在不久的將來(lái)在當(dāng)前項(xiàng)目中使用“變異測(cè)試”(從新組件開(kāi)始)。
與傳統(tǒng)的覆蓋率報(bào)告相適應(yīng),變異測(cè)試覆蓋率實(shí)際上可以衡量您的測(cè)試質(zhì)量,不能像傳統(tǒng)的覆蓋率報(bào)告那樣被愚弄。
如果您也有興趣:
- 請(qǐng)查看克里斯·里默(Chris Rimmer)的這個(gè)非常有趣的演講 ,內(nèi)容涉及突變測(cè)試的基本概念。
- 此外,還有一家名為TheLadders的公司使用PIT突變測(cè)試工具撰寫(xiě)了一篇有趣的文章 。
- Filip van Laenen還寫(xiě)了一篇有關(guān)超載雜志第108版中的“變異測(cè)試”的文章。
- 最后但并非最不重要的一點(diǎn)是PIT突變測(cè)試網(wǎng)站上的文檔。
翻譯自: https://www.javacodegeeks.com/2014/03/joy-of-coding-and-mutation-testing-in-java.html
總結(jié)
以上是生活随笔為你收集整理的编码的喜悦……以及Java中的变异测试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 怎么加回删掉的微信好友
- 下一篇: Java 8 Friday Goodie