unit-testing Handledning
Komma igång med enhetstest
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;
}
}