Edytuj stronę Odnośniki Fold/unfold all ODT export Ta strona jest tylko do odczytu. Możesz wyświetlić źródła tej strony ale nie możesz ich zmienić. ~~REVEAL~~ ====== Testy jednostkowe ====== ===== Unit test - co to jest? ====== **Test jednostkowy** (ang. //unit test//) to technika testowania tworzonego oprogramowania poprzez wykonywanie testów weryfikujących poprawność działania pojedynczych elementów (jednostek) programu - np. metod, obiektów. Testowany fragment programu poddawany jest testowi, który wykonuje go i porównuje wynik z oczekiwanymi wynikami. <wrap lo>Źródło: [[wp>Test_jednostkowy|pl.wikipedia.org]]</wrap> ==== ==== * **Test jednostkowy** \\ to fragment kodu, który sprawdza inny fragment kodu\\ * **Unit**\\ najmniejsza testowalna część aplikacji * funkcja * klasa * metoda ==== Aksjomaty testowania ==== * Testy są: czasochłonne, kosztowne, ryzykowne, nużące * Żadnego realnego oprogramowanie nie da się przetestować całkowicie. * Test nie udowadnia braku błędów, a udowadnia jedynie to, ze ich nie znaleźliśmy * Nie wszystkie znalezione błędy zostaną naprawione (za duży koszt, brak czasu, ryzyko naprawy) * Paradoks pestycydów - błędy w oprogramowaniu uodparniają się na testy * Testowanie wymaga wyobraźni i złośliwości * Czy warto tracić czas na pisanie testów ? ==== Czym są testy jednostkowe? ==== {{:zajecia:npr:unit-test-blak-box.jpg?800|}} ==== Przykład: klasa testowana ==== <code csharp> public class Kalkulator { public int Suma(int [] x) { if (x == null) throw new ArgumentNullException(); int s = 0; for(int i=1; i < x.Length ; i++) s+=x[i]; return s; } } </code> ==== Przykład: klasa testowa ==== <code csharp> public class KalkulatorTest { public void SumaTest() { int[] x = { 1, 2, 3, 4 }; Kalkulator c = new Kalkulator(); int oczekiwanyWynik = 10; int aktualnyWynik = c.Suma(x); if (aktualnyWynik != oczekiwanyWynik) throw new Exception($"Test oblany: spodziewana wartosc {oczekiwanyWynik}, aktualna wartosc {aktualnyWynik}"); } } </code> ==== ==== <code csharp> public class KalkulatorTest { public void SumaTestException() { Kalkulator c = new Kalkulator(); try { c.Suma(null); } catch (ArgumentNullException) { return; } throw new Exception("Test oblany"); } } </code> ==== Przykład: środowisko uruchomieniowe ==== <code csharp> class Program { static void Main(string[] args) { KalkulatorTest test = new KalkulatorTest(); test.SumaTest(); test.SumaTestException(); Console.WriteLine("Wszystkie testy zaliczone."); } } </code> ==== ==== **Porażka** | {{zajecia:npr_2015_1:kalkulator_failed2.png?1000|}} | **Sukces** | {{zajecia:npr_2015_1:kalkulator_passed2.png?1000|}} | ==== Przykład: VS2012 MS Test ==== <code csharp> [TestClass] public class UnitTestKalkulator { [TestMethod] public void TestSuma10() { // arrange int[] x = { 1, 2, 3, 4 }; Kalkulator c = new Kalkulator(); int oczekiwanyWynik = 10; //act int aktualnyWynik = c.Suma(x); //assert Assert.AreEqual(oczekiwanyWynik, aktualnyWynik); } } </code> ===== Test-driven development (TDD) ===== Technika zwinna (agile), wywodząca się z programowania ekstremalnego. {{zajecia:npr_2015_1:tdd.jpg|}} <wrap lo>Źródło: [[wp>Test-driven_development|Test-driven development]] [[http://msdn.microsoft.com/pl-pl/library/test-driven-development.aspx|Wstęp do Test Driven Development (MSDN)]]</wrap> ==== ==== * Test -> code -> refactor * najpierw test sprawdzający dodawaną funkcjonalność (test nieudany) * implementacja funkcjonalności (test udany) * refaktoryzacja napisanego kodu, żeby spełniał on oczekiwane standardy. ==== Korzyści TDD i testowania ==== * Wczesne wykrywanie błędów -> mniejszy koszt * Odporność oprogramowania na błędy regresyjne, czyli błędy powstałe w wyniku poprawek kodu * Ułatwienie refaktoringu i zmian w kodzie pokrytym testami * Dokumentowanie i wyjaśnianie kodu. Test wyjaśnia jaką funkcjonalność realizuje jednostka kodu i jak należy jej używać. * Lepiej zaprojektowane interfejsy i API. Testy zmuszają do lepszego przemyślenia rozwiązań i dokładnego określenia jakie zadania dana metoda ma wykonywać. * Testy mogą pełnić rolę specyfikacji projektowej (TDD) podobnej do UML. * Uproszczona integracja, łatwiejsze łączenie różnych fragmentów kodu poddanych wcześniej testom. Testowanie bottom-up. Jednak zbiór UT nie zastąpi testów systemowych (które najczęściej są wykonywane ręcznie) * Automatyzacja i powtarzalność (contignous integration): testy można uruchamiać regularnie o określonych porach lub na pewnych etapach produkcji. Oszczędność czasu w stosunku do ręcznego testowania. * Możliwość przetestowania funkcjonalności bez uruchamiania całego oprogramowania ===== Wzorce w testowaniu jednostkowym ===== Wzorzec AAA: Arrange -> Act -> Assert - przygotowanie środowiska testowego (Fixtures) - ustawienie stanu wejściowego - uruchomienie testowanych jednostek kodu (Act) - porównanie uzyskanych wyników (Assert) - zwolnienie zasobów (Teardown) ==== xUnit ==== * Wzorzec **xUnit** - zbiór środowisk testowych (frameworks) wywodzących swoją architekturę od SUnit (Kent Beck, 1998, Smaltalk). * **Assercje** - funkcje weryfikujące stan i zachowanie jednostek kodu. Zazwyczaj w postaci wyrażenia logicznego, które zwraca albo prawdę albo fałsz. Niepowodzenie przerywa dany test (rzucany wyjątek). * **Test runner** - program uruchamiający testy i raportujący wyniki * **Test fixtures** (test context) - zbiór warunków wymaganych do przeprowadzenia testu * **Test suites** - zbiór testów uruchamianych w jednym środowisku (fixture). Kolejność uruchomienia nie ma znaczenia. ===== Unit Test Frameworks ===== Narzędzia i biblioteki wspierające tworzenie testów, ich organizację, automatyzację wykonywania, raportowanie * Biblioteka asercji i innych metod przydatnych przy testowaniu * Automatyzacja w procesie wytwórczym * Generatory testów, testy parametryczne * Mechanizmy izolacji: fake, mock, itd * Metryki: pokrycie kodu, ścieżek, ... ==== Środowiska testowe ==== * Java -> [[http://junit.org/|JUnit]], [[http://testng.org/doc/index.html|TestNG]] * PHP -> [[https://phpunit.de/index.html|PHPUnit]] * C -> [[https://github.com/siu/minunit|MinUnit]], [[http://cunit.sourceforge.net/|CUnit]], (biblioteka assert.h), [[https://cmocka.org/|cmocka]] * C%%++%% -> [[http://freedesktop.org/wiki/Software/cppunit/|CppUnit]], [[http://www.qa-systems.com/cantata.html|Cantata]], [[https://code.google.com/p/googletest/|GoogleTest]], [[http://www.boost.org/doc/libs/1_57_0/libs/test/doc/html/index.html|Boost Test Library]] * .Net -> Visual Studio Unit Testing Framework (MS Test, VS Prof./Ultimate), [[http://www.nunit.org/|NUnit]], [[http://xunit.github.io/|xUnit.net]] * Python -> [[http://pyunit.sourceforge.net/|PyUnit]] * [[http://www.mathworks.com/help/matlab/matlab-unit-test-framework.html|MATLAB Unit Testing Framework]] * Delphi -> DUnit, Fortran -> pFUnit Wikipedia: [[wp>List_of_unit_testing_frameworks|List of unit testing frameworks]] ==== .NET frameworks ==== * Unit Test: * MS Test, [[http://www.nunit.org/|Nunit]], [[https://xunit.github.io/|XUnit.net]], MBUnit * [[https://xunit.github.io/docs/comparisons.html|Porównanie]] * Frameworki izolacji * [[https://github.com/Moq/moq4|Moq]] The most popular and friendly mocking framework for .NET * [[http://www.hibernatingrhinos.com/oss/rhino-mocks|Rhino mock]] * [[http://fakeiteasy.github.io/|FakeItEasy]] The easy mocking library for .NET * [[http://nsubstitute.github.io/|NSubstitute]] A friendly substitute for .NET mocking frameworks * wiele innych: NMock, Typemock, ... ==== Przykład: MS Test ==== <code csharp> using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] public class UnitTestKalkulator { private Kalkulator _calc; [TestInitialize] public void Init() { _calc = new Kalkulator(); } [TestMethod] public void TestSuma10() { int[] x = { 1, 2, 3, 4 }; int oczekiwanyWynik = 10; int aktualnyWynik = _calc.Suma(x); Assert.AreEqual(oczekiwanyWynik, aktualnyWynik); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void TestSumaException() { _calc.Suma(null); } } </code> ==== Przykład: NUnit/MBUnit ==== <code csharp> using NUnit.Framework; [TestFixture] public class UnitTestKalkulator { private Kalkulator _calc; [SetUp] public void Create() { _calc = new Kalkulator(); } [Test] public void TestSuma10() { int[] x = { 1, 2, 3, 4 }; int oczekiwanyWynik = 10; int aktualnyWynik = _calc.Suma(x); Assert.AreEqual(oczekiwanyWynik, aktualnyWynik); } [Test] [ExpectedException(typeof(ArgumentNullException))] public void TestSumaException() { _calc.Suma(null); } } </code> ==== Przykład: xUnit.net ==== <code csharp> using Xunit; public class KalkulatorTest { private Kalkulator _calc; public KalkulatorTest() { _calc = new Kalkulator(); } [Fact] public void TestSuma() { int[] x = { 1, 2, 3, 4 }; int oczekiwanyWynik = 10; int aktualnyWynik = _calc.Suma(x); Assert.Equal(oczekiwanyWynik, aktualnyWynik); } [Fact] public void TestSumaException() { Assert.Throws<ArgumentNullException>(() => _calc.Suma(null)); } } </code> ===== Dobrze napisane testy ===== * Test wyłącznie pojedynczej jednostki, nie można pisać testów badających kilka funkcji naraz * Testy powinny być niezależne od siebie * Izolacja: testy niezależne od zewnętrznych zasobów, są one zastępowane makietami symulującymi ich działanie (mock, fake, stub, ...) * Przejrzystość - testy wyjaśniają i dokumentują kod * Szybkość - testy powinny wykonywać się szybko, to nie są testy wydajności * Konwencje nazewnicze - nazwa testu oddaje intencje * Pisz kod tak aby był łatwy do testowania ==== Scenariusze ==== * **Analiza ścieżek** - badanie przebiegu możliwych ścieżek od punktu początkowego do końcowego, wszystkie możliwe kombinacje rozgałęzień * Boundary test - działania w pętli pomijane lub pętla uruchamiana raz (dla wszystkich ścieżek) * Interior test - działania we wnętrzu pętli uważa się za przetestowane, jeśli zostały wykonane wszystkie ścieżki, które są możliwe przy dwukrotnym powtórzeniu pętli ==== ==== * **Klasy równoważności** - zbiór danych o podobnym sposobie przetwarzania. Testujemy wybrane elementy ze zbioru. na wejściu kilka elementów przetwarzanych w ten sam sposób * klasy poprawności/niepoprawności - przypadki dla których przewidujemy poprawne/niepoprawne działanie \\ Np. ''{2, 4, 70)'' dla liczb dodatnich całkowitych * **Wartości brzegowe** - wewnątrz, pomiędzy lub na granicy klas równoważności \\ Np. ''{-1, 0, 2, 4, 70)'' dla liczb dodatnich całkowitych ==== Zakres dostępu ==== * **metody publiczne**, testowane bez problemu * **metody chronione** - nie można w bezpośredni sposób wywołać metody chronionej ze sterownika testu. Rozwiązaniem jest stworzenie klasy opakowującej dziedziczącej po badanej klasie i wywołanie chronionych metod w dziedziczącej klasie bazowej * **metody prywatne** - za pomocą mechanizmu refleksji można ominąć ograniczenia i wywołać prywatną metodę. * Czy testy jednostkowe powinny dotyczyć wyłącznie metod publicznych? ==== Testy prywatnych metod ==== Klasa {{https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.privateobject.aspx|PrivateObject}} pozwala opakować klasę zawierającą prywatne elementy do testowania. Dostęp do prywatnych elementów za pomocą metody ''Invoke()'' <code csharp> using Microsoft.VisualStudio.TestTools.UnitTesting; [TestMethod] public void TestPrywatnejMetody() { var obj = new PrivateObject(typeof(KlasaZPrywatnąMetodą)); var wynik = obj.Invoke("PrywatnaMetoda"); Assert.AreEqual(wynik, spodziewanyWynik); } </code> ===== Rodzaje testów ===== * Widoczność: * Testy funkcjonalne (czarna skrzynka), zazwyczaj wykonywanie przez osoby nie wytwarzające kodu. \\ Testy black-box: acceptance, fuzz, smoke, performance (load, stress) * Testy strukturalne (biała/przezroczysta skrzynka), test ma wgląd w testowany kod. \\ Testy white-box: unit, regression, integration, mutation ==== ==== * Skala: * jednostkowe - pojedyncze funkcjonalności * systemowe - testy aplikacji jako całość: bezpieczeństwo, wymagania niefunkcjonalne, wydajność * integracyjne - współpraca komponentów, testuje współdziałanie klas i modułu ===== Testy jednostkowe w VS ===== {{ zajecia:npr_2015_1:unit_test_project_vs2012.png?600|}} Szablony projektów: Unit Test Project, Visual C#, C%%++%% * Namespace: Microsoft.VisualStudio.TestTools.UnitTesting * Wiele rozszerzeń wspierających: Resharper, [[http://www.testdriven.net/default.aspx|TestDriven.net]] ==== Generowanie metod testowych ==== {{https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/45/92/0842.CreateUnitTest.jpg?600|}} * Narzędzia do generowania projeku testowego i metod testowych dostępne w VS 2010 ale nie w 2012/13, powróciły w 2015 * Wtyczki np. {{https://visualstudiogallery.msdn.microsoft.com/45208924-e7b0-45df-8cff-165b505a38d7|Unit Test Generator}} ==== Menu test ==== * Uruchomienie wybranych testów * Debbugowanie wybranych testów * Pokrycie kodu * Okna: Test Explorer, Code Coverage Results {{zajecia:npr_2015_1:test_menu_vs2012.png?600|}} ==== VS Test Explorer ==== |{{zajecia:npr_2015_1:test_explorer_vs2012_2.png?350 |}} | {{zajecia:npr_2015_1:test_explorer_vs2012_3.png?350 |}} | ==== Typy asercji ==== * [[https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.assert.aspx|Assert Class (MSDN)]] * **AreEqual** / **AreNotEqual** - porównanie warości * **AreSame** / **AreNotSame** - porównanie referencji * **Fail** - test jednostkowy jest niezaliczony * **Inconclusive** - wykonanie testu jest nierozstrzygnięte * **IsTrue** / **IsFalse** - porównanie wartości true/false * **IsInstanceOfType** / IsNotInstanceOfType - czy dostarczona wartość nie jest podanego typu * **IsNull** / **IsNotNull** - czy dostarczona wartość nie jest NULL ==== ==== * [[https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.collectionassert.aspx|CollectionAssert]] zestaw metod testowych dla porównywania kolekcji (np. CollectionAssert.AreEqual) * [[https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.stringassert.aspx|StringAssert]] zestaw asercji do testowania napisów * **Contains** * **Matches** / **DoesNotMatch** dopasowanie wyrażenia regularnego * **StartsWith** / **EndsWith** ==== Artybuty === * **TestClass** określa klasę zawierającą metody testowe * Przygotowanie środowiska testowego (fixture/teardown) dla assembly, zestawu testów w klasie i pojedyńczej metody testowej * **AssemblyInitialize** / **AssemblyCleanup** * **ClassInitialize** / **ClassCleanup** * **TestInitialize** / **TestCleanup** * **ExpectedException** spodziewany wyjątek rzucany z testu * **Description** opis testu * **Ignore** test nie będzie uruchomiony * **TestCategory** pozwala grupować testy * **WorkItem** powiązanie testu z zadaniem (work item) [[https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.aspx|UnitTesting Namespace]] ==== Kontekst testu ==== * Klasa [[https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.testcontext.aspx|TestContext]] przechowuje informacje, które można dostarczyć do testów * Połaczenia do danych (data row, Data Driven Unit Test) * Informacje o wykonywanym teście (np. ścieżki dostępu) * Infromacje do testowania ASP.NET, np.: URL serwera Web, dostęp do obiektu Page * Dostęp do własności ''TextContext'' (tworzona automatycznie lub należy dodać ręcznie) * Metody oznaczone atrybutem ClassInitialize i AssemblyInitialize muszą dostarczyć obiekt TextContext w argumencie ==== Setup fixture ==== {{zajecia:npr_2015_1:context_mstest.png?800|}} ===== NUnit ===== {{ http://www.nunit.org/img/logo.gif| }} * xUnit dla języków .Net, początkowo port z JUnit * najpopularniejsze środowisko dla tej platformy * wersja 3.0 przepisana od nowa, obecnie wersja 3.2 * biblioteki: framework, mock * aplikacja uruchamiająca testy: GUI, console * Assercja: [[http://www.nunit.org/index.php?p=classicModel&r=2.6.4|classic model]] vs. [[http://www.nunit.org/index.php?p=constraintModel&r=2.6.4|Constraint-Based Assert Model]] (NUnit 2.4) ==== GUI ==== {{zajecia:npr_2015_1:nunit_main_window.png?800|}} ==== CLI ==== {{zajecia:npr_2015_1:nunit_console.png?800|}} ===== xUnit.net ===== {{ https://raw.github.com/xunit/media/master/full-logo.png|}} "xUnit.net is a free, open source, community-focused unit testing tool for the .NET Framework. Written by the original inventor of NUnit v2, xUnit.net is the latest technology for unit testing C#, F#, VB.NET and other .NET languages. xUnit.net works with ReSharper, CodeRush, TestDriven.NET and Xamarin." Zaprojektowany z myślą o maksymalnym uproszczeniu testowania ==== ==== Pakiety NuGet * ''xUnit.net'' framework * ''xunit.runner.console'' uruchamianie testów w konsoli * ''xunit.runner.visualstudio'' integracja z Test Explorer w VS * Wtyczka do Resharpera: runner for xUnit.net {{http://xunit.github.io/|xUnit website}}\\ [[https://xunit.codeplex.com/wikipage?title=Comparisons|Porównanie: NUnit vs. MS Test vs. xUnit]] ===== Data Driven Unit Test ===== * Metody testowe mogą pobierać dane do testów ze źródeł dostępnych na maszynach uruchamiających testy <code csharp> [DataSource(@"Provider=Microsoft.SqlServerCe.Client.4.0; Data Source=C:\Data\MathsData.sdf;", "Numbers")] [TestMethod] public void AddIntegers_FromDataSourceTest() { var target = new Maths(); // Access the data int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]); int y = Convert.ToInt32(TestContext.DataRow["SecondNumber"]); int expected = Convert.ToInt32(TestContext.DataRow["Sum"]); int actual = target.IntegerMethod(x, y); Assert.AreEqual(expected, actual); } </code> <wrap lo>Źródło: [[https://msdn.microsoft.com/en-us/library/ms182527.aspx|How To: Create a Data-Driven Unit Test]] </wrap> ===== Xunit.net: Teorie ===== <code csharp> [Theory] [InlineData(3)] [InlineData(5)] [InlineData(6)] public void MyFirstTheory(int value) { Assert.True(IsOdd(value)); } bool IsOdd(int value) { return value % 2 == 1; } } </code> * w NUnit bardzo szeroki zakres parametryzacji za pomocą odpowiednich atrybutów ==== ==== <code csharp> [Theory] [PropertyData("SplitCountData")] public void SplitCount(string input, int expectedCount) { var actualCount = input.Split(' ').Count(); Assert.Equal(expectedCount, actualCount); } public static IEnumerable<object[]> SplitCountData { get { // Or this could read from a file. :) return new[] { new object[] { "xUnit", 1 }, new object[] { "is fun", 2 }, new object[] { "to test with", 3 } }; } } </code> <wrap lo>Zródło: {{http://www.tomdupont.net/2012/04/xunit-theory-data-driven-unit-test.html|Theory DDT}}</wrap>, Tom DuPont ===== Skip i Timeout ===== <code csharp> [Fact(Skip="Trait Extensibility is not working in 1654"), Category("Slow Test")] public void LongTest() { Thread.Sleep(500); } [Fact, Trait("Category", "Supa")] public void LongTest2() { Assert.True(true); } [Fact(Timeout=50)] public void TestThatRunsTooLong() { System.Threading.Thread.Sleep(250); } </code> ===== AutoFixture ===== * [[https://github.com/AutoFixture|AutoFixture]] is an open source library for .NET designed to minimize the 'Arrange' phase. * Tworzenie anonimowych zmiennych <code csharp> [TestMethod] public void IntroductoryTest() { // Fixture setup Fixture fixture = new Fixture(); int expectedNumber = fixture.Create<int>(); MyClass sut = fixture.Create<MyClass>(); // Exercise system int result = sut.Echo(expectedNumber); // Verify outcome Assert.AreEqual<int>(expectedNumber, result, "Echo"); // Teardown } </code> ===== AutoData ===== <code csharp> [Theory, AutoData] public void IntroductoryTest(int expectedNumber, MyClass sut) { int result = sut.Echo(expectedNumber); Assert.Equal(expectedNumber, result); } </code> ===== Techniki izolacji ===== * Izolacja: test jednostkowy nie może wykraczać poza zakres testowanej jednostki kodu * Testy wykraczające poza ten zakres * to testy integracji * są wolniejsze * mogą się nie powieść ze względu na błędy w tych zewnętrznych modułach ==== ==== * Separacja od zewnętrznych procesów wymusza tworzenie kodu bardziej modularnego, prostszego w testowaniu i ponownym wykorzystaniu (dependency inversion principle, warstwy abstrakcji pomiędzy komunikującymi się modułami) * Obiekty imitujące dostęp do zewnętrznych procesów: Fake, Mock, Stub, Spies, Exstract and Override, .... * Frameworks .NET: [[https://github.com/Moq/moq4|Moq]], [[https://github.com/FakeItEasy/FakeItEasy|FakeItEasy]], [[http://www.hibernatingrhinos.com/oss/rhino-mocks|RhinoMocks]], [[http://nsubstitute.github.io/|NSubstitute]], ... ==== Mock objects ==== * **Atrapy obiektów** (mock objects) - symulowane obiekty naśladujące w kontrolowany sposób zachowanie rzeczywistych obiektów. * symulowanie połączenia do bazy danych * symulowanie z zasobami, które mogą być niedostępne, np.: połączenia z serwisami sieciowymi * symulowanie obiektów, które jeszcze nie powstały * symulowanie w celu zwiększenia szybkości testów * Obiekty Fake i Mock realizują wzorzec [[wp>Dependency injection]] ==== Mocks, fakes i inne ==== * Wzorce [[http://xunitpatterns.com/Test%20Double%20Patterns.html|Test Doubles]], różnią się przede wszystkim sposobami wykorzystania * Dummy - zwraca pewną domyślna wartość * Stub - pozwala zwracać więcej wartości, bardziej złożona logika wewnętrzna * Spy * Fake - metody tego obiektu dostarczają niezbędne dane do działania testu * Mock - to obiekt Fake zawierający w sobie assercję testową lecz nie tylko * Inne: strict mock, dynamic mock, loose mock, substitute, mole. ==== ==== * "no need to learn what’s the theoretical difference between a mock, a stub, a fake, a dynamic mock, etc." (Moq project) * "all fake objects are just that — fakes. Usage determines whether they're mocks or stubs." (FakeItEasy) ==== Dependency Injection ==== * **Wstrzykiwanie zależności** - wzorzec projektowy i wzorzec architektury oprogramowania polegający na usuwaniu bezpośrednich zależności pomiędzy komponentami na rzecz architektury typu plug-in. Szczególna realizacja paradygmatu z odwróceniem sterowania sterowania (Inversion of Control, IoC). \\ * Wstrzyknięcie przez : konstruktor, settery, interfejs * DI pozwala wstrzyknąć do obiektów testowanych zależności od obiektów-zaślepek (atrap, mock objects), w ten sposób TTD narzuca stosowanie dobrych praktyk ==== Przykład DI ==== <code csharp> public class Client { // Wewnętrzna referencja do usługi private Service service; // Wstrzyknięcie przez konstruktor Client(Service service) { this.service = service; } // Metoda w której klient korzysta z usługi (chcemy wyizolować to działanie) public double Compute(double x) { return x * service.GetSomeValue(); } } </code> ==== Przykład: biblioteka Moq ==== <code csharp> // Tworzymy obiekt atrapę var mockClient = new Mock<Service>(); // Ustawiamy metodę aby zwracała symulowaną wartość mockClient.Setup(mock => mock.GetSomeValue()).Returns(1); // Wstrzykujemy atrapę do obiektu który będzie testowany var client = new Clent(mockClient.Object); // Test Assert.IsEqual(client.Compute(2), oczekiwanaWartosc); </code> ===== Pokrycie kodu (code coverage) ===== Pokrycie kodu mierzy, ile procent kodu zostało sprawdzone przez testy jednostkowego. Przyjmuje się, że dobrze napisane testy powinny mieć pokrycie rzędu przynajmniej 70% . ==== Metryki pokrycia ==== * **Pokrycie wyrażeń** (ang. statement coverage) – metryka stanowi iloraz liczby linii kodu wywołanych przez testy jednostkowe oraz całkowitej liczby linii kodu. Jeśli jakaś linia nie została pokryta, istnieje zatem ryzyko wystąpienia w niej błędu. * **Pokrycie rozgałęzień** (ang. branch coverage) – pokrycie nie bada linii kodu, a rozgałęzienia zrealizowane za pomocą np. instrukcji if (czy test przetestował ścieżki true i false) * **Pokrycie ścieżki** (path coverage) - ścieżka to unikatowa sekwencja rozgałęźień w funkcji * inne: pokrycie funkcji/metod, klas (metod w klasach)/ patch coverage ==== Code coverage w VS ==== * VS2010: Test -> Edit Test Settings -> Local * Data and Diagnostic -> Code Coverag * Configure - wybór źródła danych do analizy * VS2012: Test -> Analyze Code Coverage -> All Tests/ Selected Test | {{zajecia:npr_2015_1:code_coverage_results_vs2012.png?600|}} | {{zajecia:npr_2015_1:code_coverage_coloring_vs2012.png?500|}} | ==== Testowanie mutacyjne ==== **Testowanie mutacyjne** – technika automatycznego badania, na ile dokładnie testy jednostkowe sprawdzają kod programu. Polega na automatycznym wielokrotnym wprowadzaniu małych losowych błędów w programie i uruchamianiu za każdym razem testów jednostkowych, które powinny te błędy wykryć. Testowanie mutacyjne wymaga dużej mocy obliczeniowej i dlatego dopiero od niedawna próbuje się je wykorzystywać w praktyce. <wrap lo>Źródło: [[wp>Testowanie_mutacyjne|pl.wikipedia.pl]]</wrap> ===== Testy w Resharper ===== * Środowisko uruchomieniowe : MS Test, NUnit, xUnit.net (wtyczka do R#) {{zajecia:npr_2015_1:resharper_test_menu.png|}} ==== Unit test explorer ==== {{zajecia:npr_2015_1:resharper_test_explorer.png|}} ==== Unit test sesions ==== {{zajecia:npr_2015_1:resharper_sessions.png|}} ==== dotTrace i DotCover ==== * profilowanie testów dotTrace Performance * Pokrycie kodu DotCover {{https://www.jetbrains.com/dotcover/img/30/report.png?600|}} ===== Integracja z TFS ===== * Uruchamianie testów w po stronie serwera - konfugiracja buldów * Raporty z wykonanych testów {{zajecia:npr:tfs-build-def-with-test2.png?800|}} ===== Podsumowanie ===== * Testy jednostkowe nie dają 100% pewności, że kod nie posiada błędów * Należy stosować je wraz z innymi testami: testy integracyjne, systemowe, obciążeniowe itd. * Nie wszystko da się przetestować: zachowania niedeterministyczne, aplikacje wielowątkowe * Na jedną linię kodu może przypadać nawet do 5 linii kodu testu - nie zawsze jest to opłacalne * Kod testujący jak każdy inny kod nie jest odporny na błędy ===== Bibliografia ===== * [[http://msdn.microsoft.com/pl-pl/library/testy-jednostkowe-w-visual-studio.aspx|Testy jednostkowe w Visual Studio]] * Jeremy Lindblom, [[https://speakerdeck.com/jeremeamia/unit-testing|Unit Testing]] * [[wp>List_of_unit_testing_frameworks|List of unit testing frameworks]] * [[http://xunitpatterns.com/|XUnit Test Patterns]], Gerard Meszaros * [[http://www.codethinked.com/beginning-mocking-with-moq-3-part-1|Beginning Mocking With Moq 3]] by Justin Etheredge ([[http://www.codethinked.com/beginning-mocking-with-moq-3-part-2|part 2]], [[http://www.codethinked.com/beginning-mocking-with-moq-3-part-3|part 3]], [[http://www.codethinked.com/beginning-mocking-with-moq-3-part-4|part 4]]) * {{http://video.ch9.ms/sessions/teched/eu/2014/Labs/DEV-H211.pdf|Introduction to unit testing}} * [[https://msdn.microsoft.com/en-us/library/dd264975.aspx|Verifying Code by Using Unit Tests]] (MSDN)