一、變異測試簡介
變異測試是一種基于故障注入的測試技術,将錯誤代碼插入到被測代碼中,以驗證目前測試用例是否可以發現注入的錯誤。我認為該測試手段理論上屬于白盒測試範疇。
變異測試的主要目的是為了驗證測試用例的有效性,在注入變異後,測試用例能發現該錯誤,則表明用例有效的;反之,表明測試用例是無效的,需要補充該變異的測試用例。
變異測試有助于評估測試用例的品質,以幫助測試人員編寫更有效的測試用例。測試人員設計的測試用例發現的變異體越多,表明其設計的測試用例品質就越高。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5CN3IjM4YWOyITMiJTYlJTNzYzXzITM1IDMyIzLcBTMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
在深入了解變異測試之前,讓我們先搞懂和它相關的幾個核心概念。
1) 變異
可以了解為對源代碼的任何更改,也可以了解為引入的故障。
2) 變異體
可以了解為被測代碼的變異版本,即已經在被測代碼中注入變異的代碼。當測試用例在變異體版本的代碼運作時,理論上該測試用例執行的結果應該與原被測代碼執行的結果不同。
- 存活的(survived)變異體:變異注入的錯誤并不能被測試用例感覺,這種情況稱為變異體能夠“存活”,說明測試用例的有效性存在問題,需要對測試用例進行補充和修正。
- 殺死的(killed)變異體:在變異體代碼上執行測試不通過,說明變異注入的錯誤能夠被測試用例T感覺到,測試用例能夠“殺死”此變異,說明此測試用例是有效的。
- 等價的變異體:這個其實也很好了解,通過下面例子介紹下。
源代碼:
for(int i=0;i<10; i++){ // 源程式 //To-do ... }
變體1:
for(int i=0;i!=10; i++){ //變體1 //To-do ... }
變體2:
for(int i=0;i<10; i--){ //變體2 //To-do ... }
其中變體1與源代碼是等價的:都是i從0開始,經曆1,2,3,4,5,6,7,8,9到10,在源代碼中由于10<10傳回False,退出循環;在變體1中由于10!=10傳回False,退出循環。
3) 變異分
變異分也稱為變異充分性,這是基于測試用例發現變異體數量計算出來的分數,計算公式如下:
注意,在計算變異分時不會考慮等價的變異體。
二、如何進行變異測試
下面通過JavaScript代碼做示範,使用Jasmine測試架構寫單測用例。
1.編寫原被測代碼
const user_info = () =&gt; {
mother_age = parseInt(prompt("Enter mother's age"))
daughter_age = parseInt(prompt("Enter daughter's age"))
if (mother_age &gt; daughter_age) {
alert(`Daughter's age is ${daughter_age}. Mother's age is
${mother_age}. Welcome to the Mother-Daughter program`)
} else {
alert(`Daughter's age: ${daughter_age}, is more than mother's age: ${mother_age}.
Please enter correct ages`)
}
}
user_info();
2.編寫 Jasmine 單元測試用例
describe("User", function() {
it("should compare the two numbers from user input", function(){
expect(20).toBeGreaterThan(5);
})
});
3.在原始代碼運作測試,以確定測試用例都是通過的
Daughter's age is 5. Mother's age is 20. Welcome to the Mother-Daughter program
4.注入變異
我們将">"運算符 (mother_age >daughter_age) 更改為"<"運算符 (mother_age <daughter_age)
5.在變異版本上運作測試
Daughter's age: 5, is more than mother's age: 20. Please enter correct ages
6.比較源代碼和變異版本代碼運作測試的結果
通過運作結果發現,雖然二者使用相同的測試用例,但是運作結果是不一樣的,是以,我們的測試用例“殺死”了變異,也說明我們的測試用例是有效的。
三、變異測試類型
1) 值變異
通過改變參數值來實作代碼變異,例如在原值基礎上+/- 1。
原始代碼
上面的代碼邏輯是将i<4的偶數相乘,那麼通過值變異可以将初始化值由let i=0更改為let i=1。
變異代碼
2) 語句變異
通過删除、重複或颠倒代碼塊中的語句實作代碼變異。
例如,在 if-else 語句塊中,重複console.log代碼。
原始代碼
變異代碼
3) 運算符變異
通過修改代碼中的運算符來實作代碼變異,例如常見的值比較邏輯。我們可以将> 更改為 <。
原運算符 | 運算符變異 | |
1 | <= | >= |
2 | >= | == |
3 | === | == |
4 | and | or |
5 | || | && |
四、變異測試優缺點分析
- 可以覆寫大部分代碼邏輯。
- 可以測試特定部分代碼,而不僅僅是通過路徑、分支或語句方式實作。
- 可以幫助我們評估測試用例的品質并進行優化。
- 變異測試需要在單元測試已經做得比較完備的基礎上才有其價值。