Krzysztof Manuszewski

Slides:



Advertisements
Podobne prezentacje
Zaawansowane Techniki Obiektowe
Advertisements

Temat 2: Podstawy programowania Algorytmy – 1 z 2 _________________________________________________________________________________________________________________.
Rozwój infrastruktury sportowej w Gminie Wyszków Analiza wariantowa.
Systemy oceny jakości Akredytacja w ochronie zdrowia vs ISO 9000 Jerzy Hennig Andrzej Warunek.
OBOWIĄZKI INFORMACYJNE BENEFICJENTA Zintegrowane Inwestycje Terytorialne Aglomeracji Wałbrzyskiej.
Tworzenie odwołania zewnętrznego (łącza) do zakresu komórek w innym skoroszycie Możliwości efektywnego stosowania odwołań zewnętrznych Odwołania zewnętrzne.
GRUPY I ZESPOŁY © dr E.Kuczmera-Ludwiczyńska, mgr D.Ludwiczyński.
InMoST, Analiza architektury metodą ATAM Jerzy Nawrocki
Jak rozwijać PS po zakończeniu finansowania ze środków projektowych? OWES subregion centralno-zachodni Tadeusz Durczok
Ryzyko a stopa zwrotu. Standardowe narzędzia inwestowania Analiza fundamentalna – ocena kondycji i perspektyw rozwoju podmiotu emitującego papiery wartościowe.
EWALUACJA PROJEKTU WSPÓŁFINANSOWANEGO ZE ŚRODKÓW UNII EUROPEJSKIE J „Wyrównywanie dysproporcji w dostępie do przedszkoli dzieci z terenów wiejskich, w.
Usługi socjalne dla osób starszych w Helsinkach Päivi Riikonen Satu Vihersaari-Virtanen
KOMUNIKOWANIE W PROCESIE WSPIERANIA ROZWOJU SZKOŁY Jarosław Kordziński NA.
Wypadkowa sił.. Bardzo często się zdarza, że na ciało działa kilka sił. Okazuje się, że można działanie tych sił zastąpić jedną, o odpowiedniej wartości.
OPTYMALNY CEL I PODSTAWY ROZWOJU SZKOŁY. PRZEDE WSZYSTKIM DZISIEJSZA SZKOŁA POWINNA PRZYGOTOWYWAĆ DO ŻYCIA W DRUGIEJ POŁOWIE XXI WIEKU.
Algorytmy Informatyka Zakres rozszerzony
ZTO Wprowadzenie do TDD, SOLID - Jak pisać dobry kod Krzysztof Manuszewski.
Założenia psychologii kognitywnej (poznawczej) jako innowacyjna forma pracy z uczniem realizowana w Zespole Szkół w Gębicach.
Po pierwsze: Bądź odważny! Weź los w swoje ręce, w końcu do odważnych świat należy. Niech Twoja odwaga nie oznacza jednak podejmowania ryzyka bez analizy.
Dzieci i szkolnictwo w Mali. Warunki życia dzieci Jednym z największych problemów w kraju jest bardzo wysoki współczynnik umieralności dzieci do 5. roku.
„Gdański model aktywizacji społeczności lokalnych” Gdańsk, 27 kwietnia 2009.
Model warstwowy OSI Model OSI (Open Systems Interconnection) opisuje sposób przepływu informacji między aplikacjami programowymi w jednej stacji sieciowej.
Komunikatory Zespół Szkół Zawodowych Nr 3 im. Adama Kocura w Katowicach - Janowie.
Budżet rodzinny Projekt współfinansowany przez Unię Europejską w ramach Europejskiego Funduszu Społecznego.
Czym jest gramofon DJ-ski?. Gramofon DJ-ski posiada suwak Pitch służący do płynnego przyspieszania bądź zwalniania obrotów talerza, na którym umieszcza.
Python. Języki Programistyczne Microcode Machine code Assembly Language (symboliczna reprezentacja machine code) Low-level Programming Language (FORTRAN,
Wprowadzenie do baz danych. Terminologia Specyfika baz danych (1) 1.Trwałość danych –Długi czas życia – kilka, kilkadziesiąt, kilkaset lat –Niezależność.
Jak się uczymy? ● 3 P (presentation, practice, production) ● Po wykonaniu zadania ktoś musi powiedzieć czy zrobiliśmy je dobrze... ● Jeśli ciekawie przedstawimy.
Język Java Paweł Rajba
Dziedziczenie, polimorfizm, Interfejsy
Hoopl Higher-order optimization library
Test analizy wariancji dla wielu średnich – klasyfikacja pojedyncza
Rola książki w życiu człowieka
Programowanie Obiektowe – Wykład 1
T.15 Wybór narzędzi dla reengineeringu (szczegóły).
Komunikacja ze szkołą i nauczycielami - dziennik elektroniczny
Wyznaczanie miejsc zerowych funkcji
Wytwarzanie oprogramowania sterowane przypadkami testowymi
DEFINICJA I ZASTOSOWANIE W JĘZYKU HASKELL
On-the-Fly Garbage Collection
Mikołaj Radwan JUnit Mikołaj Radwan
Liczby pierwsze.
„Prawa Ceteris Paribus i socjo-ekonomiczne mechanizmy”
„Łączą nas efekty projektów” – wymagania programowe a doświadczenia po pierwszych naborach w Programie Interreg V-A Polska – Słowacja
Akademia C# - Lab2 Zmienne, instrukcje warunkowe, pętle, debugger,
Akademia C# lab. 9 Zdarzenia i delegaty.
Zasady zdrowego odżywiania
Programowanie obiektowe
Optymalizacja programów Open-Source
Lekcja 1 – Hello World! Visual Studio, coś łatwego na początek 
Kurs języka C++ – wykład 13 ( )
Git - system kontroli wersji
Bezpieczeństwo dostępu do danych w systemie Windows
Języki programowania.
Trzy wyzwania medycyny personalizowanej - perspektywa pacjentów:
Laboratorium 1 – obsługa wejść i wyjść
Koszyk danych.
SYSTEM KONTROLI FREKWENCJI
Podstawy informatyki Zygfryd Głowacz.
Strukturalne wzorce projektowe
Proste obliczenia w arkuszu kalkulacyjnym
Damian Urbańczyk Edytory WYSIWYG.
Implementacja rekurencji w języku Haskell
Tytuł prezentacji szkoleniowej
Język C++ Operatory Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła.
Program na dziś Wprowadzenie Logika prezentacji i artykułu
GRUBA RYBA jak się robi SEO dla naprawdę dużych klientów
dr Danuta Kajrunajtys BUSINESS PROCESS MANAGEMENT ROBOTIC PROCESS
Autor: Magdalena Linowiecka
„Junit”.
Zapis prezentacji:

Krzysztof Manuszewski ZTO Testy jednostkowe Krzysztof Manuszewski

W czym pomagają testy jednostkowe? Ułatwiają znajdowanie błedów Ułatwiają zrozumienie kodu Ułatwiają utrzymanie kodu Ułatwiają pisanie kodu

Testy jednostkowe Testy weryfikują na bieżąco konkretne aspekty zachowania klas. Złamanie założeń powoduje załamanie konkretnych testów. Przy dodawaniu/zmianach funkcjonalności testy chronią przed zepsuciem już zaimplemen-towanych funkcji. Przy TDD/BDD pokazują czy osiągnęliśmy założony cel. Stanowią dokumentację i zarazem przykłady użycia Kod powinień być pisany prosto. Działający kod można i należy udoskonalać. Aby to było bezpieczne potrzebne są testy.

Test jednostkowy Jest to automatyczny fragment kodu uruchamiający i weryfikujący poprawność wykonania pewnego aspektu kodu produkcyjnego Testy są pisane z wykorzystaniem framework-ów. Dzięki temu mogą być stworzone i uruchamiane szybko i łatwo: .Net: np. NUnit, MSTest, MBUnit, Xunit, MSpec Testy mogą być uruchamiane pojedynczo lub masowo przez każdego członka zespołu lub w procesie automatycznego budowania (CI/CD) Testy są częścią projektu (trzeba o nie dbać!) ale nie są dostarczane do klientów

Test jednostkowy – elementy (1) bool IsLoginOk(string user, string password); [TestFixture] Class TestClass { [Test] public void TestLogin1() { LoginComponent sut = new AuthComponent (); bool result = sut.IsLoginOk("user","password"); Assert.IsFalse(result, "invalid user/password shouldn't be accepted"); }

NUnit Dedykowane GUI Wtyczki do VS: R# TestDriven.Net

Części testu czyli AAA Arrange – utwórz SUT/subject, zainicjuj środowisko Act – wykonaj test Assert – sprawdź wyniki Przygotowanie może być realizowane Np. w SetUp

Test jednostkowy – wspólny set-up [TestFixture] Class TestClass { AuthComponent sut; [SetUp] public void Init() { sut = new AuthComponent (); } public void TestLogin1() { … } [Test] public void TestLogin2() { var result = sut.IsLoginOk("Iksinski","realPassword"); Assert.IsTrue(result,"valid user/password should be acceprted"); }

Gdzie leży problem czy nazwy byly dobre? wspólny setup, co to znaczy? skad wiadomo, że "Iksinski" jest poprawnym uzytkownikiem

Gdzie leży problem Kod produkcyjny powinien być dobrze przetestowany. Test powinien się jasno nazywać i powinien testować pojedynczy aspekt działania Nie należy pisać niepotrzebnych testów Kod testów powinien zawierać jak najmniej powtórzeń Testy powinny być zrozumiałe a ich kod powinien być dobrej jakości

Dlaczego Kod produkcyjny powinien być dobrze przetestowany ... Jeśli testy maja "dziury" – nie można im w pełni zaufać (czy można ufać troche?) To znaczy nie powinna udać się żadna istotna zmiana kodu produkcyjnego bez zepsucia jednego lub wielu testów Jeśli znajdujemy problem w kodzie produkcyjnym – dodajemy nowy test/testy a potem poprawiamy kod. Testy powinny być stabilne i niezależne. Fałszywe alarmy to duży problem!

Co testować Logikę. Instrukcje warunkowe Pętle Testowanie prostych properties/funkcji mija się z celem. Publiczny interfejs. Jeżeli metody prywatne zawierają nietrywialna logikę może to znak, że klasa powinna zostać zrefaktoryzowana. Np. samochód vs. silnik

Życie prywatne klasy Jeżeli testy wymagają dostępu do niepublicznych składników np. dla weryfikacji stanu (niepokojące...) : Nie należy rozhermetyzować klasy Można dodać klasę potomną dla potrzeb testu (składniki protected) Można rozważyć użycie refleksji…

Dlaczego Test powinien się jasno nazywać Testy powinny wskazywać na konkretne problemy - dobre nazwy zwalniają ze szczegółowych komunikatów przy asercjach Niejasna nazwa przy wielu testach (np. tysiącach) powoduje, że musimy przebijać się przez logi, debugować/analizować kod Nazwa testu powinna dobrze lokalizować błąd. Najlepiej bez debugowania, bez analizy komunikatów Jeśli mamy problem z nazwą testu – jest bardzo prawdopodobne, że próbujemy przetestować zbyt wiele rzeczy na raz

Jasno czyli jak ? Czy porzednie testy miały dobra nazwę? Konwencje LoginComponent_InvalidUser_ShuldThrowException WhenUserIsInvalid. IsLoginOk_ShouldThrowException Trudno nazwać test, który dotyczy wielu aspektów zachowania klasy Przy dobrej nazwie komunikatów może nie być

Dlaczego Test powinien … testować pojedynczy aspekt działania kodu to znaczy poszczególne zmiany w kodzie produkcyjnym powinny "zapalać" jak najmniej testów Test, który testuje wiele rzeczy bedzie częściej "padać" przy zmianach kodu Test, który testuje wiele rzeczy jest skomplikowany Test, który testuje wiele rzeczy niewiele mówi w momencie upadku Aspekt niekoniecznie znaczy jedna klasa, funkcja itd.

Dlaczego Nie należy pisać niepotrzebnych testów Pisanie testów kosztuje. Utrzymanie testów kosztuje jeszcze więcej. Jeśli 2 testy padają zawsze razem – jeden jest niepotrzebny – oba testują to samo Jeśli test pada zawsze z jednym spośród kilku innych – jest niepotrzebny Pokusa by testować to co testują inne testy prowadzi do tego, że testy padają częściej niż by mogły

Dlaczego Kod testów powinien zawierać jak najmniej powtórzeń ... Duplikacja to ZŁO : Utrudniona poprawa testów/rozwój kodu (Rak testów) Jak unikać powtórzeń wspólny Setup (ale nie tak ze jest jedne setup dla wszystkich testów – podejscie wolne i niejasne) Hierarchia klas, Buildery danych testowych własne asserty Własne asercje, Metody weryfikujące Testy sterowane danymi Uwaga: wywołanie konstruktora (np. new osoba(...)) - to też powtórzenie!

Dlaczego Testy powinny być zrozumiałe... Test stanowi dokumentację Przed zmianą funkcjonalności (albo zaraz po) należy zmienić test(y) Boje się zmieniać tego czego nie rozumiem!!! Testy nie powinny zawierać logiki – jak testować testy? Jeśli test zawiera logikę należy ją wydzielić (np. do funkcji). Takie funkcje mozna przetestować.

Dlaczego … kod testów powinien być dobrej jakości co to znaczy dobra jakość? Krótki, zrozumiały kod, dobre nazewnictwo, Brak powtórzeń Testy zmieniają się równie często co kod (albo częściej) Testy nie trafiają do klienta ale są podstawą pracy programisty Błędy w testach sa równie złe co w kodzie. Powolna praca z testami jest równie zła co powolna praca z kodem. Testy można i należy refaktoryzować

Jak pisać testy - podsumowanie Dobrej jakości testy nie wymagają intensywnej pielęgnacji. Projekty (agile) raczej padają z powodu złej jakości testów a nie nie z powodu ich braku Kod nie może zawierać "hack-ów" (if test ....) Test, który zawsze działa – nic nie testuje. Zawsze należy sprawdzić czy są przypadki gdy test zawodzi Typowy kod jest trudny do testowania. Testy dla istniejącego (i stabilnego kodu) mają umiarkowany sens: poznawanie kodu przygotowanie do zmiany kodu

Testy sterowane danymi Pojedynczy kod testu (parametryzowany) Test jest uruchamiany wielokrotnie dla różnych zestawów danych Dane dla testu mogą być umieszczone w kodzie lub brane z zewnętrznych źródeł (txt, xml, csv, xls, mdb itd.) UWAGA: to nie jest "silver bullet" Słaba diagnostyka Tendencja do testowania kombinatorycznego

Testy sterowane danymi MSTest [TestClass] public class TestClass { [TestMethod] [DeploymentItem("Cipher.MDB")] [DataSource("System.Data.OleDb", "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\" Cipher.MDB \"", "Employees", DataAccessMethod.Sequential)] public void TestEncryptionMethod() var key = TestContext.DataRow["key"]; var phrase = TestContext.DataRow["text"]; var sut = new Cryptography(key); var encrypted = sut.EncryptText(phase); assert.AreEqal(encrypted, TestContext.DataRow["encryptedText"] ); }

Testy sterowane danymi NUnit [TestCase(2.5d, 2d, Result=1.25d)] [TestCase(-2.5d, 1d, Result = -2.5d)] public double ValidateDivision(double numerator, double denominator) { var myClass = new MyClass(); return myClass.Divide(numerator,denominator); }

Dlaczego TDD/BDD Red/Green/Refactor Test = specyfikacja funkcjonalności Test = projekt rozwiązania (wywołanie) Pewność, że test działa Lepsze wyczucie za jaki aspekt odpowiada konkretny test Test powinien weryfikować dany aspekt Test powinien dokumentować dany aspekt (być specyfikacją) Problem: należy sie skupić na jednym aspekcie. Nie próbować implementować za dużo.

Jak używać testów? Są często (stale?) uruchamiane podczas kodowania Są cyklicznie uruchamiane na serwerze buildów. Testy odzwierciedlają kontrakt pomiędzy użytkownikiem i dostarczycielem funkcjonalności Testy stanowią wyznacznik jakości architektury kodu -> testy mogą służyć tworzeniu dobrej architektury (TDD/BDD) Należy "słuchać" co mówią testy – jak łatwo/trudno je utrzymać.

Filozofia: definiowania testów Jeden po drugim: przyrostowy development Wszystkie na raz: np definiujemy pojedyncze user story jako sekwencje testów Wady drugiego podejścia Nie wiadomo, który test za co odpowiada Brak wyczucia nt. ew. nadmiarowości testów Masowe podejście – łatwiej coś przeoczyć

Struktura kodu testowego Testy można grupować w klasy - test fixtures (np. dla wspólnej inicjalizacjj SUT) Jedna klasa testowa nie musi (i zwykle nie odpowiada) jednej klasie testowanej raczej konkretnym danym testowym Czesto (zwykle?) dla pojedynczej funkcji piszemy kilka testów: jeden test - jeden aspekt działania funkcji (jeden asert logiczny)

Filozofia: budowa test fixture Up front Łatwo o błedny projekt Niepotrzebny kod – YAGNI (You aren't gonna need it) Test po teście: Nie należy pisać kodu na wyrost Przyrostowy development Fresh Fixture

Inicjalizacja Sut SUT = system under test Instancja SUT nie powinna być współdzielona pomiędzy wieloma testami Wrażliwość na kolejnośc wykonania Trudna diagnostyka SUT może być kazdorazowo inicjowany w teście lub inicjowany w SetUp. To drugie podejście ułatwia unikanie redundancji. Ale należy unikać wielkich, nie do końca wspólnych setupów.

Testowanie zachowania Izolacja klas

Filozofia: co testować Stan obiektów Zachowanie obiektów: Testujemy wołania innych funkcji/obiektów Zasada proś [o przysługę] nie pytaj [o stan] Jak trzeba mieszamy podejścia Przede wszystkim należy testować to co ma wartość z punktu widzenia klienta

Zachowanie ... public class InvoiceProcessor { private ISender sender; private ILogger logger; public InvoiceProcessor(ISender nSender, ILogger nLogger) { sender = newSender; logger = nLogger; } public bool Process(...) { logger.Log("start"); if (...) { ... bool ret = sender.Send(invoice); ... } } var procesor = new InvoiceProcesor(new InvoiceSender(...), new Logger()); TEST

...to nie stan Problem 1: ignorujemy zachowanie kodu logger.Log() Problem 2: nie mamy skonfigurowanego sendera –czy sender.Send() zwrócil true czy false Problem 3: czy sender zostal wywolany i z jakimi paramerami

Wymagane zastępstwo Problem 1: Problem 2: public class FakeLogger : Ilogger { public void Log(string msg) {} } Problem 2: public class FakeSender : ISender { public bool Ret = true; public bool Send (obiect toSend) { return Ret; }

Wymagane zastępstwo Problem 3: public class FakeSenderValidator : ISender { public bool Ret = true; public bool SendWasCalled = false; public object SendArgument; public bool Send (object toSend) { SendWasCalled = true; SendArgument = toSend; return Ret; } }

Bez nowych klas... Stub: – obiekt kreowany dynamicznie – akceptujący wołania i ew. zwracający konkretne wartości Mock: – obiekt kreowany dynamicznie – z mozliwością weryfikacji konkretnych zachowań Mocking frameworks: Nmock, Moq – stosunkowo proste Rhino mock – bardzo zaawansowany TypeMock – jeszcze bardziej zaawansowany ale ... komercyjny

Przykład 1, 2 [Test] public void Process_whenSendingSuccesful_...() { //Problem1: var logger = MockRepository.GenerateStub<ILogger>(); //Problem2: var sender = MockRepository.GenerateStub<ISender>(); sender. Stub(s => s.Send(null)). IgnoreArguments(). Return(true); InvoiceProcessor sut = new InvoiceProcessor(sender, logger); var result = Sut.Process(....); ... }

Przykład 3 [Test] public void Process_whenSendingSuccesful_...() { var logger = MockRepository.GenerateStub<ILogger>(); var sender = MockRepository.GenerateStub<ISender>(); sender. Stub(s => s.Send(null)). IgnoreArguments(). Return(true); Invoice invoice = ...; InvoiceProcessor sut = new InvoiceProcessor(sender, logger); var result = Sut.Process(invoice); ... //Problem 3: sender.AssertWasCalled( s => s.Send(invoice) ); }

Problemy przy testach Niejawne wejście - środo-wisko zewnetrzne np.: Pojawienie się pliku Brak pamieci Pojawienie się procesu Otrzymanie maila Przyciśnięcie przycisku w GUI Zmiana danych w bazie Niejawne wyjście – efekt działania kodu np.: Skasowanie pliku Zabicie procesu Wysłanie maila Wyświetlenie czegoś na ekranie, zmiana stanu elementow GUI Zapis danych do bazy

Trudny test public void StartMonitoring(...) { ... if (System.IO.File.Exists("myFile")) //send email } Niejawne wejście Niejawne wyjście

Dedykowana Podklasa class SystemMonitor{ public void StartMonitoring(...) { ... if (FileExists("myFile")) SendEmail(...) } protected virtual bool FileExists(string fileName) { return System.IO.File.Exists(fileName); } protected virtual bool SendEmail (...) { //send email

Dedykowana Podklasa class SystemMonitorTestSubclas : SystemMonitor { public bool fileExists = true; public bool emailSent = false; public virtual void SendEmail(...) { emailSent = true; } public virtual bool FileExists (...) { return fileExists; } } var sut = new SystemMonitorTestSubclas (); A z mockiem: var sut = MockRepository.GeneratePartialMock< SystemMonitor >(); sut.Stub(s => s.FileExist (null)).IgnoreArguments().Return(true); sut.Stub(s => s.SendEmail(null)).IgnoreArguments(); .... sut.StartMonitoring(); sut.AssertWasCalled( s => s.SendEmail(null), options => IgnoreArguments());

Obiekty izolujący class SystemMonitor { private FileSystemProvider fileSystem; private MailSenser sender; public void StartMonitoring(...) { ... while(...) { ... if (fileSystem.FileExists("myFile")) sender.SendEmail(...) }

Narzędzia Frameworki UT Mocking tools: Kontenery IOC Automocking xUnit MSpec Mocking tools: TypeMock Isolator RhinoMock Mocq Microsoft Fakes Kontenery IOC Automocking Specyfikacja wymagań SpecFlow

Warto poczytać, popatrzeć ... Andy Hunt, Dave Thomas "Pragmatic Unit Testing in C# with Nunit" Roy Osherove "The Art of Unit Testing with Examples in .NET" Gerard Meszaros "xUnit Test Patterns" http://www.ayende.com/wiki/Rhino+Mocks.ashx Prezenacje wideo: "Roy Osherove - Understanding Test Driven Development.wmv" "Roy Osherove - Unit Testing Best Practices.wmv" "Roy Osherove - Test Driven Development, Using Mock Objects.wmv"