Sök…


Anmärkningar

Enhetstest beskriver processen för att testa enskilda kodenheter isolerat från systemet som de är en del av. Vad som utgör en enhet kan variera från system till system, allt från en individuell metod till en grupp nära relaterade klasser eller en modul.

Enheten isoleras från beroenden med hjälp av testdubblar vid behov och ställs in i ett känt tillstånd. Dess beteende som reaktion på stimuli (metodsamtal, händelser, simulerade data) testas sedan mot det förväntade beteendet.

Enhetstestning av hela system kan göras med hjälp av anpassade skriftliga testsele, men många testramar har skrivits för att hjälpa till att effektivisera processen och ta hand om mycket av VVS, repetitiva och vardagliga uppgifter. Detta gör att utvecklare kan koncentrera sig på vad de vill testa.

När ett projekt har tillräckligt med enhetstester kan alla ändringar av att lägga till ny funktionalitet eller utföra en kodrefaktoring enkelt göras genom att i slutet kontrollera att allt fungerar som tidigare.

Kodtäckning , normalt uttryckt i procent, är den typiska metriken som används för att visa hur mycket av koden i ett system som omfattas av enhetstester; Observera att det inte finns någon hård och snabb regel om hur högt detta ska vara, men det accepteras allmänt att ju högre, desto bättre.

Testdriven utveckling (TDD) är en princip som anger att en utvecklare bör börja koda genom att skriva ett fel på enhetstest och först därefter skriva den produktionskod som får testet att klara. När man utövar TDD kan man säga att testerna själva är den första konsumenten av koden som skapas; därför hjälper de till att granska och driva utformningen av koden så att den är så enkel att använda och så robust som möjligt.

versioner

Enhetstestning är ett koncept som inte har versionnummer.

Ett grundläggande enhetstest

Enhetstest består som enklast av tre steg:

  • Förbered miljön för testet
  • Kör koden som ska testas
  • Validera det förväntade beteendet matchar det observerade beteendet

Dessa tre stadier kallas ofta 'Arranger-Act-Assert' eller 'given-When-Then'.

Nedan är exempel i C # som använder NUnit- ramverket.

[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);             
  }
}

Vid behov rensas en fjärde rengöringsstadium som tillval.

Ett enhetstest med stoppad beroende

Bra enhetstester är oberoende, men koden har ofta beroenden. Vi använder olika typer av testdubblar för att ta bort beroenden för testning. En av de enklaste testdubblarna är en stubb. Detta är en funktion med ett hårdkodat returvärde som kallas i stället för den verkliga beroendet.

// 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

I produktionskod skulle oneDayFromNow ringa Date.now (), men det skulle göra för inkonsekventa och opålitliga tester. Så här stubbar vi ut det.

Ett enhetstest med spion (interaktionstest)

Classic enhet testar provtillstånd, men det kan vara omöjligt att korrekt testmetoder vars beteende beror på andra klasser genom staten. Vi testar dessa metoder genom interaktionstester , som verifierar att systemet som testas korrekt kallar sina medarbetare. Eftersom samarbetarna har sina egna enhetstester är detta tillräckligt och faktiskt ett bättre test av det testade metodens faktiska ansvar. Vi testar inte att den här metoden returnerar ett visst resultat som ges en inmatning, utan att den istället kallar sin samarbetspartner.

// 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

Enkelt Java + JUnit-test

JUnit är den ledande testramen som används för att testa Java-kod.

Klassen under testet modellerar ett enkelt bankkonto, som debiterar en påföljd när du blir överdrivet.

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
        }
    }
}

Den här testklassen validerar beteendet hos vissa av de offentliga metoderna för BankAccount .

import org.junit.Test;
import static org.junit.Assert.*;

// Class that tests
public class BankAccountTest{

    BankAccount acc;

    @Before                        // This will run **before** EACH @Test
    public void setUptestDepositUpdatesBalance(){
        acc = new BankAccount(100);  
    } 

    @After                        // This Will run **after** EACH @Test
    public void tearDown(){
    // clean up code
    }

    @Test
    public void testDeposit(){
       // no need to instantiate a new BankAccount(), @Before does it for us

        acc.deposit(100);

        assertEquals(acc.getBalance(),200); 
    }

    @Test
    public void testWithdrawUpdatesBalance(){    
        acc.withdraw(30);

        assertEquals(acc.getBalance(),70); // pass
    }

    @Test
    public void testWithdrawAppliesPenaltyWhenOverdrawn(){

        acc.withdraw(120);

        assertEquals(acc.getBalance(),-30);
    }
}

Enhetstest med parametrar med NUnit och 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);
        }
    }
}

Ett grundläggande test av Python-enhet

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) 

Nu testdelen:

class Test_SystemUnderTest(unittest.TestCase):

    def test_addition(self):
        """test addition function"""

        # use only one summand - raise an error 
        with self.assertRaisesRegexp(ValueError, 'at least two summands'):
            addition(1)
        
        # use None - raise an error
        with self.assertRaises(TypeError):
            addition(1, None)
        
        # use ints and floats 
        self.assertEqual(addition(1, 1.), 2)

        # use complex numbers
        self.assertEqual(addition(1, 1., 1+2j), 3+2j)

if __name__ == '__main__':
    unittest.main()

Ett XUnit-test med parametrar

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;
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow