Szukaj…


Uwagi

Testowanie jednostkowe opisuje proces testowania poszczególnych jednostek kodu w oderwaniu od systemu, którego są częścią. To, co stanowi jednostkę, może się różnić w zależności od systemu, od indywidualnej metody do grupy ściśle powiązanych klas lub modułu.

Jednostka jest izolowana od swoich zależności za pomocą podwójnych testów, gdy jest to konieczne i ustawiana w znany stan. Jego zachowanie w reakcji na bodźce (wywołania metod, zdarzenia, dane symulowane) jest następnie testowane pod kątem oczekiwanego zachowania.

Testy jednostkowe całych systemów mogą być wykonywane przy użyciu niestandardowych pisemnych wiązek testowych, jednak napisano wiele ram testowych, aby usprawnić proces i zająć się wieloma czynnościami hydraulicznymi, powtarzalnymi i przyziemnymi. Pozwala to programistom skoncentrować się na tym, co chcą przetestować.

Gdy projekt ma wystarczającą liczbę testów jednostkowych, dowolną modyfikację dodania nowej funkcjonalności lub wykonania refaktoryzacji kodu można łatwo zrobić, weryfikując na końcu, że wszystko działa jak poprzednio.

Pokrycie kodu , zwykle wyrażone w procentach, jest typową miarą używaną do pokazania, ile kodu w systemie jest objęte testami jednostkowymi; zwróć uwagę, że nie ma twardej i szybkiej reguły dotyczącej tego, jak wysoka powinna być ta wysokość, ale ogólnie przyjmuje się, że im wyższa, tym lepsza.

Test Driven Development (TDD) to zasada określająca, że programista powinien rozpocząć kodowanie od napisania nieudanego testu jednostkowego, a dopiero potem napisać kod produkcyjny, który przejdzie test. Ćwicząc TDD, można powiedzieć, że same testy są pierwszymi konsumentami tworzonego kodu; dlatego pomagają kontrolować i sterować projektem kodu, dzięki czemu jest on tak prosty w użyciu i jak najbardziej niezawodny.

Wersje

Testy jednostkowe to koncepcja, która nie ma numerów wersji.

Podstawowy test jednostkowy

W najprostszym przypadku test jednostkowy składa się z trzech etapów:

  • Przygotuj środowisko do testu
  • Wykonaj kod do przetestowania
  • Sprawdź, czy oczekiwane zachowanie pasuje do obserwowanego zachowania

Te trzy etapy są często nazywane „Arrange-Act-Assert” lub „Given-When-Then”.

Poniżej znajduje się przykład w języku C #, który używa frameworka NUnit .

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

W razie potrzeby porządkuje się opcjonalny czwarty etap czyszczenia.

Test jednostkowy z zalążkową zależnością

Dobre testy jednostkowe są niezależne, ale kod często ma zależności. Używamy różnego rodzaju podwójnych testów, aby usunąć zależności do testowania. Jednym z najprostszych podwójnych testów jest odgałęzienie. Jest to funkcja z zakodowaną wartością zwrotną wywoływaną zamiast zależności w świecie rzeczywistym.

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

W kodzie produkcyjnym oneDayFromNow wywołałaby Date.now (), ale spowodowałoby to niespójne i niewiarygodne testy. Więc tutaj to rozwalamy.

Test jednostkowy ze szpiegiem (test interakcji)

Klasyczne testy jednostkowe testują stan , ale prawidłowe testowanie metod, których zachowanie zależy od innych klas, może być niemożliwe. Testujemy te metody za pomocą testów interakcji , które sprawdzają, czy testowany system poprawnie wzywa swoich współpracowników. Ponieważ współpracownicy mają własne testy jednostkowe, jest to wystarczające, a właściwie lepszy test rzeczywistej odpowiedzialności za testowaną metodę. Nie testujemy, czy ta metoda zwraca określony wynik na podstawie danych wejściowych, ale zamiast tego poprawnie wywołuje swoich współpracowników.

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

Prosty test Java + JUnit

JUnit to wiodąca platforma testowa używana do testowania kodu Java.

Testowana klasa modeluje proste konto bankowe, które pobiera karę za przekroczenie kwoty.

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

Ta klasa testowa sprawdza zachowanie niektórych metod publicznych 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);
    }
}

Test jednostkowy z parametrami za pomocą NUnit i 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);
        }
    }
}

Podstawowy test jednostki 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) 

Teraz część testowa:

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()

Test XUnit z parametrami

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow