Anywhere - IT-break Milan Lempera Víťa Plšek @milanlempera @vitaplsek UnitTest.cz
O nás 0-1 Milan Lempera @milanlempera php, javascript, clojure(script) Víťa Plšek @vitaplsek java, javascript UnitTest.cz
Obsah školení 0-2 1. den Rozdělení testů Unit testy TDD Matchery Property based testing 2. den Test doubles Clean & legacy code Integrační testy E2E testy BDD Jak školení probíhá? blok teorie k tématu, potom krátká cvičení celkem je jich 9 + 2 společné code katy
O vás 0-3 1. Jaký je Váš vztah k testování? 2. Co si představujete pod pojmem čistý kód? Pokud máte dotazy, ptejte se kdykoli.
1-0
Testuje každý 1-1 když spustíte aplikaci když ji proklikáváte když si výsledek funkce vypíšete do konzole System.out.println(calculator.add(3, 5)); // 8 System.out.println(calculator.add(-3, 5)); // 2 System.out.println(calculator.add(-3, -5)); // -8
PROČ PSÁT TESTY? 1-2 opakovatelnost, znovupoužití, důvěryhodnost kódu snížení počtu chyb
Rozdělení testů 1-3 end-to-end testy integrační testy unit testy (jednotkové testy) každý z typů má své místo při vývoji software, nejsou vzájemně nahraditelné
End to end testy (E2E) 1-4 Testujete co vidí uživatel celá aplikace backend-frontend* včetně DB Ale potřebujete speciální prostředí je těžší je napsat a hůř se ladí náročnější údržba neukáží přesně zdroj chyby Je kód připravený k nasazení?
Integrační testy 1-5 testování vnitřní integrace spolupráce několika komponent Předávají si komponenty data správným způsobem, ve správný okamžik?
Unit testy 1-6 Jen znovu-použitelné "výsledky v konzoli". zaměřené na testování malé jednotky typicky třída nebo algoritmus testujeme izolovaně od dalších jednotek závislosti nahrazujeme primárně feedback pro vývojáře Naprogramoval jsem danou funkci(onalitu) správně?
Jak najít rovnováhu mezi typy testů? 1-7
Jak najít rovnováhu mezi typy testů? 1-8
Jak napsat první test? 2-0 podobně jako println debugging System.out.println(calculator.add(3, 5)); // 8 otestujeme očekávaný vstup a očekávaný výstup calculator.add(3, 5) == 8 potřebujeme knihovnu, která kontroluje rovnost hodnot a případně vypíše chybu
2-1 JUnit is a simple framework to write repeatable tests. It is an instance of the xunit architecture for unit testing frameworks. JUnit.org
JUnit - Původ 2-2 SUnit - 1994 testovací framework pro Smalltalk Kent Beck vznikl cestou ke klientovi na konzultaci JUnit - 1997 implementace SUnit v Javě Kent Beck, Erich Gamma vznikl v letadle cestou na konferenci Oopsla 97
Test v JUnit 2-3 Test v JUnit je metoda s anotací @Test, která ověřuje tvrzení. import org.junit.test; import static org.junit.assert.asserttrue; public class FirstTest { @Test public void calculatorshouldsum3and5() { } Calculator calculator = new Calculator(); assertequals(8, calculator.add(3, 5)); }
Assertion - ověření tvrzení 2-4 statické metody třídy Assert import static org.junit.assert.*; assertequals(42, allanswers.getanswer()); assertnotequals(123, allanswers.getanswer()); assertnull(department.getsupervisor()); assertnotnull(department.getsupervisor()); asserttrue(invoice.ispaid()); assertfalse(invoice.isoverdue());...
Arrange, Act, Assert - tři části testu 2-5 @Test public void shouldcalculatesum() { Calculator calculator = new Calculator(); Integer result = calculator.sum(1, 3); assertequals(result, 4); } // Arrange // Act // Assert
Spouštění testů v IDE 2-6
Ukázka - spuštění testu 2-7
Test fixture 3-0 Rozlišme jednotlivé fáze testu Set up - příprava prostředí Exercise - provedení akce Verify - vyhodnocení Tear down - úklid JUnit nám pomůže se Set up a Tear down
Test fixture 3-1 @Test public void haszerolisteners() { Resource resource = new Resource(); // set up int numoflisteners = resource.getnumoflisteners(); // exercise assertequals(0, result); // verify } resource.close(); // tear down
Test fixture v JUnit 3-2 Anotace životního cyklu nad metodami @Before - před každým testem @After - po každém testu @BeforeClass - před spuštěním třídy @AfterClass - po spuštění třídy
Test fixture v JUnit 3-3 public class ResourceTest { private Resource resource; @Before public void setup() { resource = new Resource(); } @After public void teardown() { resource.close(); } @Test public void isopened() { asserttrue(resource.isopened()); } } @Test public void haszerolisteners() { assertequals(0, resource.getnumoflisteners()); }
Životní cyklus testu 3-4 @BeforeClass setupclass --------------------------- @Before setup @Test isopened() @After teardown --------------------------- --------------------------- @Before setup @Test haszerolisteners() @After teardown --------------------------- @AfterClass teardownclass
Ukázka - refactoring testu 3-5
DALŠÍ ZPŮSOBY MATCHOVÁNÍ 4-0
Proč by Vás měly zajímat 4-1 s metodami assert* můžete vystačit...... není to ale vždy nejefektivnější Příklad - assert* Všichni na oddělení musí mít alespoň minimální mzdu @Test public void allwagesshouldbeatleastminimal() { for (Integer wage : department.getwages()) { asserttrue(wage + " is lower then minimal", wage >= MINIMAL_WAGE); } }
HAMCREST ASSERTJ 4-2
Hamcrest 4-3 Matchers that can be combined to create intent. exible expressions of hamcrest.org
Hamcrest - assertthat 4-4 Hamcrest - assertthat assertthat(actual, equalto(expected)); JUnit - assertequals assertequals(expected, actual); // syntaxe: assertthat(actual, Matcher)
Hamcrest - ukázka matcherů 4-5 hamcrest staví na skládání matherů assertthat(person.getwage(), lessthen(wage_limit)); assertthat(wages, everyitem(greaterthanorequal(minimal_wage))); assertthat(wages, not(everyitem(greaterthanorequal(minimal_wage)))); assertthat(invoices, everyitem(hasstatus(paid)));
AssertJ 4-6 AssertJ core is a Java library that provides a writing assertions. uent interface for joel-costigliola.github.io/assertj
AssertJ - assertthat 4-7 AssertJ - assertthat assertthat(actual).isequalto(expected); Hamcrest - assertthat assertthat(actual, equalto(expected); JUnit - assertequals assertequals(expected, actual);
AssertJ - řetězení matcherů 4-8 metoda assertthat nabízí asserce podle typu volání je možné řetězit, každé znamená samostatný test dobrá podpora IDE assertthat("abeceda").isequalto("abeceda").isnotequalto("zzz").startswith("abe").matches("[a-z]*")... assertthat(42).isgreaterthan(41).islessthan(43).ispositive().isbetween(0, 100)...
AssertJ - použití na objektech 4-9 assertthat(lastinvoice).isnotnull().isinstanceof(invoice.class).isequalto(invoice)....hasstatus(status.new).has(condition)
AsssertJ - práce s kolekcemi 4-10 lterování, extrakce assertthat(persons).filteredon(status(status.paid)).isnotempty().extracting("wages", BigDecimal.class).doesNotContain(BigDecimal.ZERO).are(greaterThan(MINIMAL_WAGE));
TEST DRIVEN DEVELOPMENT 5-0
Test driven development 5-1 Add a little test Run all tests and fail Make a little change Run the tests and succeed Refactor to remove duplication * Test-driven Development By Example - Kent Beck
Test driven development 5-2
Proč Test driven development? 5-3 ověření správnosti a postupu návrh řízený použitím (testem) větší zaměření na cíl získáte velmi rychlou zpětnou vazbu vývoj malých funkčních celků architekturu vznikající z implementace
Ukázka - TDD 5-4
Parametrizované testy 6-0 podobné testy, kde se mění jen vstupní data a očekávaný výstup @Test public void convertone() { int result = converter.toarabic("i"); assertequals(1, result); } @Test public void converttwo() { int result = converter.toarabic("ii"); assertequals(2, result); } { } // input, output { "I", 1 }, { "II", 2 }, { "III", 3 }
Parametrický test 6-1 @RunWith(Parameterized.class) public class RomanNumberConverterTest { private int arabicnumber; private String romannumber; public InvoiceStatusTest(Status romannumber, int arabicnumber) { this.romannumber = romannumber; this.arabicnumber = arabicnumber; } @Parameters(name="{index}: convert({0}) = {1}") public static Iterable<Object[]> testparameters() { return Arrays.asList(new Object[][]{ {"I", 1}, {"II", 2}, {"III", 3} }); } } @Test public void convertromannumbers() { assertthat(romannumberconverter.convert(romannumber)).isequalto(arabicnumber); }
Ukázka - parametrický test 6-2 @Parameterized.Parameters(name = "{index}: tobinary({0}) = {1}") public static Iterable<Object[]> testparameters() { return Arrays.asList(new Object[][]{ {0, 0}, {1, 1}, {2, 10}, {3, 11}, {4, 100}, {5, 101}, {6, 110}, {7, 111}, {8, 1000}, {9, 1001}, {10, 1010}, {11, 1011}, {12, 1100}, {13, 1101}, {14, 1110}, {15, 1111}, {16, 10000} }); }
Způsoby testování 7-0 Vstupně výstupní @Test public void invoicecansumtotalprice() { assertthat(invoice.gettotalprice()).isequalto(sumofallrows); } Testování chování @Test public void invoicereportersendsemail() { Mailer mailer = new Mailer(); Reporter invoicereporter = new InvoiceReporter(mailer); invoicereporter.report(invoice); } // byl odeslán email na správného příjemce? Pokud nelze použít skutečnou implementaci, je nutné použít dvojníka
7-1 Tasty mocking framework for unit tests in Java Umožní mockito.org vytvářet mocky ověření počty volání a předané parametry kon gurovat chování mocku sledovat a ovlivnit existující objekty
Mockito - ukázka použití 7-2 @Test public void invoicereportshouldsendmail() throws Exception { // setup Mailer mockmailer = mock(mailer.class); when(mockmailer.send(anystring(), anyinteger())).thenreturn(true); InvoiceReporter reporter = new InvoiceReporter(mockMailer); // exercise boolean status = reporter.report(paidinvoice); } // verify asserttrue(status); verify(mockmailer).send("user@email.cz", 1001);
E2E testy 8-0 testují celou aplikaci - chování z pohledu uživatele obvykle potřebují speciální prostředí a přípravu dat často jsou prováděny manuálně
E2E testy 8-1 Velmi závisí na typu aplikace desktopová aplikace konzolová aplikace REST webová aplikace programově ovládáme prohlížeč
8-2 Selenium nástroj pro automatizaci práce s prohlížečem používá se pro testování webových aplikací
Selenium IDE 8-3 Firefox plugin pro automatizaci interakce s prohlížečem
Selenium Webdriver 8-4 Slouží pro programové ovládání prohlížeče je nutné mít potřebný ovladač prohlížeče Chrome, InternetExplorer, Opera, Edge, PhantomJs
Selenium - průběh testu 8-5 přechod na testované url nalezení elementu interakce s elementem kontrola výsledku nalezení elementu ověření existence / obsahu
Selenium - ukázka testu 8-6 // přechod na testované url driver.get("http://library.cz/books/create"); // nalezení elementu WebElement bookname = formelement.findelement(by.id("book-form")); // interakce s elementy bookname.clear(); bookname.sendkeys("guide to galaxy"); formelement.submit(); WebElement title = driver.findelement(by.cssselector("div#detail > h2")); // kontrola výsledku assertthat(title.gettext()).isequalto("guide to galaxy");
Page Object Pattern 8-7 BookFormPage bookform = new BookFormPage(driver); bookform.setname("guide to galaxy"); // vrací page object podřazeného formuláře CategoryPopup categorypopup = bookform.opencategorypopup(); categorypopup.setcategory("sci-fi"); // vrací page object po přechodu na stránku detailu DetailPage detail = bookform.submit(); assertthat(detail.gettitle()).isequalto("guide to galaxy");
Page Object Pattern - ukázka 8-8 public class BookFormPage { WebElement form; public BookFormPage(WebDriver driver) { form = wait.until( ExpectedConditions.presenceOfElementLocated(By.id("book-form")));... } public void setname(string name) { form.findelement(by.id("book-name")).settext(name); } public CategoryPopup opencategorypopup() {... return new CategoryPopup(driver, form); } }...
Ukázka - Selenium 8-9
Behavior driven development 9-0 neboli vývoj řízený popisem chování nezaměřuje se primárně na testování, ale na návrh na software se díváme z perspektivy speci kace speci kace je zároveň testem ověřujícím správnost psána obecným jazykem srozumitelná pro neprogramátory
Gherkin 9-1 Business Readable, Domain Speci c Language Feature: Serve coffee Coffee should not be served until paid for Coffee should not be served until the button has been pressed If there is no coffee left then money should be refunded Scenario: Buy last coffee Given there are 1 coffees left in the machine And I have deposited 1$ When I press the coffee button Then I should be served a coffee But It is the last one
Java, Javascript, PHP,.NET, Clojure, Ruby... 9-2
Implementace kroku 9-3 Scenario: Buy last coffee Given there are 1 coffees left in the machine When I press the coffee button Then I should be served a coffee Implementace anotace s popisem kroku @Given, @When, @And, @But, @Then public class CoffeeSteps { @Given("^there are (\\d+) coffees left in the machine$") public void therearecoffeesleftinthemachine(int count) { coffees = CoffeeTestHelper.createCoffees(count); } }
Ukázka - Cucumber 9-4
Testování je třeba trénovat 10-0 testování je soft-skill, měly byste ho trénovat průběžně testujte trénujte - code katy choďte trénovat s ostatními coderetreat.cz codingdojo.cz
Školení testování 10-1 2. - 3. května
Materiály a osnova 10-2 unittest.cz/it-break-testing