開始進行單元測試

Download unit-testing eBook

備註

單元測試描述了獨立於它們所屬系統的各個代碼單元的測試過程。構成單位的內容因係統而異,從單個方法到一組密切相關的類或模塊。

在必要時使用測試雙精度將單元與其依賴關係隔離並設置為已知狀態。然後針對預期行為測試其對刺激(方法調用,事件,模擬數據)的反應行為。

整個系統的單元測試可以使用自定義編寫的測試工具來完成,但是已經編寫了許多測試框架來幫助簡化流程並處理大量的管道,重複和平凡的任務。這允許開發人員專注於他們想要測試的內容。

當項目有足夠的單元測試時,通過最終驗證一切都像以前一樣工作,可以輕鬆完成添加新功能或執行代碼重構的任何修改。

代碼覆蓋率 ,通常表示為百分比,是用於顯示單元測試涵蓋系統中代碼量的典型度量標準;請注意,關於這應該有多高,並沒有嚴格的規則,但人們普遍認為越高越好。

測試驅動開發(TDD)是一個原則,規定開發人員應該通過編寫失敗的單元測試來開始編碼,然後才能編寫使測試通過的生產代碼。在練習TDD時,可以說測試本身是所創建代碼的第一個消費者;因此,它們有助於審計和驅動代碼的設計,使其盡可能簡單易用。

版本

單元測試是一個沒有版本號的概念。

帶參數的XUnit測試

using Xunit;

public class SimpleCalculatorTests
{
    [Theory]
    [InlineData(0, 0, 0, true)]
    [InlineData(1, 1, 2, true)]
    [InlineData(1, 1, 3, false)]
    public void Add_PassMultipleParameters_VerifyExpected(
        int inputX, int inputY, int expected, bool isExpectedCorrect)
    {
        // Arrange
        var sut = new SimpleCalculator();

        // Act
        var actual = sut.Add(inputX, inputY);

        // Assert
        if (isExpectedCorrect)
        {
            Assert.Equal(expected, actual);
        }
        else
        {
            Assert.NotEqual(expected, actual);
        }
    }
}

public class SimpleCalculator
{
    public int Add(int x, int y)
    {
        return x + y;
    }
}
 

一個基本的python單元測試

import unittest

def addition(*args):
    """ add two or more summands and return the sum """

    if len(args) < 2:
        raise ValueError, 'at least two summands are needed'
    
    for ii in args: 
        if not isinstance(ii, (int, long, float, complex )):
            raise TypeError

    # use build in function to do the job
    return sum(args) 
 

現在測試部分:

import unittest

def addition(*args):
    """ add two or more summands and return the sum """

    if len(args) < 2:
        raise ValueError, 'at least two summands are needed'
    
    for ii in args: 
        if not isinstance(ii, (int, long, float, complex )):
            raise TypeError

    # use build in function to do the job
    return sum(args) 
 

基本單元測試

最簡單的是,單元測試包括三個階段:

  • 準備測試環境
  • 執行要測試的代碼
  • 驗證與觀察到的行為匹配的預期行為

這三個階段通常被稱為'Arrange-Act-Assert',或'Given-When-Then'。

下面是使用NUnit框架的C#中的示例。

[TestFixture]
public CalculatorTest
{
   [Test]
   public void Add_PassSevenAndThree_ExpectTen()
   {
       // Arrange - setup environment
       var systemUnderTest = new Calculator();         

       // Act - Call system under test
       var calculatedSum = systemUnderTest.Add(7, 3);  
       
       // Assert - Validate expected result
       Assert.AreEqual(10, calculatedSum);             
  }
}
 

必要時,可選的第四個清理階段進行整理。

帶間諜的單元測試(交互測試)

經典單元測試測試狀態 ,但是通過狀態正確測試行為依賴於其他類的方法是不可能的。我們通過交互測試來測試這些方法,這些測試驗證被測系統正確調用其協作者。由於合作者有自己的單元測試,這就足夠了,實際上是對測試方法的實際責任的更好測試。我們不測試此方法在給定輸入的情況下返回特定結果,而是測試其正確調用其協作者。

// Test that squareOfDouble invokes square() with the doubled value

let systemUnderTest = new Calculator()          // Arrange - setup environment
let square = spy()
systemUnderTest.setSquare(square)               //   inject a spy

let actual = systemUnderTest.squareOfDouble(3)  // Act - Call system under test

assert(square.calledWith(6))                    // Assert - Validate expected interaction
 

具有存根依賴性的單元測試

好的單元測試是獨立的,但代碼通常具有依賴性。我們使用各種測試雙精度來刪除測試的依賴性。最簡單的測試雙打之一是存根。這是一個帶有硬編碼返回值的函數,代替現實世界的依賴。

// Test that oneDayFromNow returns a value 24*60*60 seconds later than current time

let systemUnderTest = new FortuneTeller()       // Arrange - setup environment
systemUnderTest.setNow(() => {return 10000})    //   inject a stub which will 
                                                //   return 10000 as the result

let actual = systemUnderTest.oneDayFromNow()    // Act - Call system under test

assert.equals(actual, 10000 + 24 * 60 * 60)     // Assert - Validate expected result
 

在生產代碼中, oneDayFromNow 會調用Date.now(),但這會導致不一致和不可靠的測試。所以在這裡我們將其刪除。

簡單的Java + JUnit測試

JUnit是用於測試Java代碼的領先測試框架。

被測試的課程模擬了一個簡單的銀行賬戶,當您透支時收取罰款。

public class BankAccount {
    private int balance;

    public BankAccount(int i){
        balance = i;
    }

    public BankAccount(){
        balance = 0;
    }

    public int getBalance(){
        return balance;
    }

    public void deposit(int i){
        balance += i;
    }

    public void withdraw(int i){
        balance -= i;
        if (balance < 0){
            balance -= 10; // penalty if overdrawn
        }
    }
}
 

此測試類驗證某些BankAccount 公共方法的行為。

public class BankAccount {
    private int balance;

    public BankAccount(int i){
        balance = i;
    }

    public BankAccount(){
        balance = 0;
    }

    public int getBalance(){
        return balance;
    }

    public void deposit(int i){
        balance += i;
    }

    public void withdraw(int i){
        balance -= i;
        if (balance < 0){
            balance -= 10; // penalty if overdrawn
        }
    }
}
 

使用NUnit和C#的參數單元測試

using NUnit.Framework;

namespace MyModuleTests 
{
    [TestFixture]
    public class MyClassTests
    {
        [TestCase(1, "Hello", true)]
        [TestCase(2, "bye", false)]
        public void MyMethod_WhenCalledWithParameters_ReturnsExpected(int param1, string param2, bool expected)
        {
        //Arrange
        var foo = new MyClass(param1);

        //Act
        var result = foo.MyMethod(param2);

        //Assert
        Assert.AreEqual(expected, result);
        }
    }
}
 

Stats

228 Contributors: 13
Monday, September 12, 2016
許可下: CC-BY-SA

不隸屬於 Stack Overflow
Rip Tutorial: info@zzzprojects.com

下載電子書