Поиск…


замечания

В модульном тестировании описывается процесс тестирования отдельных блоков кода отдельно от системы, частью которой они являются. То, что составляет единицу, может варьироваться от системы к системе, начиная от индивидуального метода и заканчивая группой тесно связанных классов или модуля.

Блок изолирован от своих зависимостей, используя тестовые удваивает, когда необходимо, и настраивается в известное состояние. Его поведение в реакции на стимулы (вызовы методов, события, смоделированные данные) затем проверяется на ожидаемое поведение.

Единичное тестирование целых систем может быть выполнено с использованием специальных письменных тестовых жгутов, однако многие тестовые структуры были написаны для упрощения процесса и ухода за большой частью сантехнических, повторяющихся и мирских задач. Это позволяет разработчикам сосредоточиться на том, что они хотят проверить.

Когда проект имеет достаточно модульных тестов, любая модификация добавления новых функций или выполнения рефакторинга кода может быть легко выполнена путем проверки в конце, что все работает по-прежнему.

Кодовое покрытие , обычно выраженное в процентах, является типичной метрикой, используемой для отображения того, какая часть кода в системе покрывается Unit Tests; обратите внимание, что нет жесткого и быстрого правила о том, как высоко это должно быть, но общепризнано, что чем выше, тем лучше.

Test Driven Development (TDD) - это принцип, который указывает, что разработчик должен начать кодирование, написав неудачный модульный тест и только потом написать производственный код, который пропустит тест. При практике TDD можно сказать, что сами тесты являются первым потребителем создаваемого кода; поэтому они помогают проводить аудит и управлять дизайном кода, чтобы он был прост в использовании и максимально надежным.

Версии

Модульное тестирование - это концепция, которая не имеет номеров версий.

Базовый единичный тест

В своем простейшем, единичный тест состоит из трех этапов:

  • Подготовьте среду для тестирования
  • Выполнить проверенный код
  • Проверка ожидаемого поведения соответствует наблюдаемому поведению

Эти три этапа часто называются «Arrange-Act-Assert» или «Given-When-Then».

Ниже приведен пример на C #, который использует структуру 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);             
  }
}

Там, где это необходимо, добавляется дополнительная четвертая ступень очистки.

Единичный тест с заглубленной зависимостью

Хорошие модульные тесты независимы, но код часто имеет зависимости. Мы используем различные типы тестов для удаления зависимостей для тестирования. Один из простейших двойных тестов - заглушка. Это функция с жестко закодированным значением возврата, называемым вместо реальной зависимости.

// 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 (), но это приведет к непоследовательным и ненадежным тестам. Итак, здесь мы это исключаем.

Единичный тест со шпионом (тест взаимодействия)

Классический блок тестирует состояние теста, но может быть невозможно правильно проверить методы, поведение которых зависит от других классов через состояние. Мы тестируем эти методы с помощью тестов взаимодействия , которые проверяют, что тестируемая система правильно называет своих сотрудников. Поскольку у коллаборационистов есть свои собственные модульные тесты, этого достаточно и на самом деле лучше проверить фактическую ответственность тестируемого метода. Мы не проверяем, что этот метод возвращает конкретный результат с учетом ввода, но вместо этого он правильно называет его соавтор (ы).

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

Простой тест 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 .

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

Unit Test с параметрами с использованием 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);
        }
    }
}

Базовый тестовый блок 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) 

Теперь тестовая часть:

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

Тест 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;
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow