天天看點

猿創征文|聊聊“高大上“的變異測試(Mutation Testing)

一、變異測試簡介

變異測試是一種基于故障注入的測試技術,将錯誤代碼插入到被測代碼中,以驗證目前測試用例是否可以發現注入的錯誤。我認為該測試手段理論上屬于白盒測試範疇。

變異測試的主要目的是為了驗證測試用例的有效性,在注入變異後,測試用例能發現該錯誤,則表明用例有效的;反之,表明測試用例是無效的,需要補充該變異的測試用例。

變異測試有助于評估測試用例的品質,以幫助測試人員編寫更有效的測試用例。測試人員設計的測試用例發現的變異體越多,表明其設計的測試用例品質就越高。

猿創征文|聊聊“高大上“的變異測試(Mutation Testing)

在深入了解變異測試之前,讓我們先搞懂和它相關的幾個核心概念。

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) 變異分

變異分也稱為變異充分性,這是基于測試用例發現變異體數量計算出來的分數,計算公式如下:

猿創征文|聊聊“高大上“的變異測試(Mutation Testing)

注意,在計算變異分時不會考慮等價的變異體。

二、如何進行變異測試

下面通過JavaScript代碼做示範,使用​​Jasmine​​測試架構寫單測用例。

1.編寫原被測代碼

const user_info = () =&amp;gt; {
  mother_age = parseInt(prompt("Enter mother's age"))
  daughter_age = parseInt(prompt("Enter daughter's age"))

  if (mother_age &amp;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.在原始代碼運作測試,以確定測試用例都是通過的

猿創征文|聊聊“高大上“的變異測試(Mutation Testing)
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)

猿創征文|聊聊“高大上“的變異測試(Mutation Testing)

5.在變異版本上運作測試

猿創征文|聊聊“高大上“的變異測試(Mutation Testing)
Daughter's age: 5, is more than mother's age: 20. Please enter correct ages      

6.比較源代碼和變異版本代碼運作測試的結果

通過運作結果發現,雖然二者使用相同的測試用例,但是運作結果是不一樣的,是以,我們的測試用例“殺死”了變異,也說明我們的測試用例是有效的。

三、變異測試類型

1) 值變異

通過改變參數值來實作代碼變異,例如在原值基礎上+/- 1。

原始代碼

猿創征文|聊聊“高大上“的變異測試(Mutation Testing)

上面的代碼邏輯是将i<4的偶數相乘,那麼通過值變異可以将初始化值由let i=0更改為let i=1。

變異代碼

猿創征文|聊聊“高大上“的變異測試(Mutation Testing)

2) 語句變異

通過删除、重複或颠倒代碼塊中的語句實作代碼變異。

例如,在 if-else 語句塊中,重複console.log代碼。

原始代碼

猿創征文|聊聊“高大上“的變異測試(Mutation Testing)

變異代碼

猿創征文|聊聊“高大上“的變異測試(Mutation Testing)

3) 運算符變異

通過修改代碼中的運算符來實作代碼變異,例如常見的值比較邏輯。我們可以将> 更改為 <。

原運算符 運算符變異
1 <= >=
2 >= ==
3 === ==
4 and or
5 || &&

四、變異測試優缺點分析

  • 可以覆寫大部分代碼邏輯。
  • 可以測試特定部分代碼,而不僅僅是通過路徑、分支或語句方式實作。
  • 可以幫助我們評估測試用例的品質并進行優化。
  • 變異測試需要在單元測試已經做得比較完備的基礎上才有其價值。

五、變異測試工具推薦