SlideShare une entreprise Scribd logo
1  sur  36
Kręta droga do dobrych testów
Mateusz Sulima
Dlaczego testujemy?
Rola testów
•  Pozwalają bezpiecznie wprowadzać zmiany
•  Najlepsza dokumentacja
•  Upraszczają refaktoring
•  Wymuszają refaktoring
•  Przyspieszają rozwój oprogramowania
Złe zrozumienie roli testów
•  Zielony słupek w Sonarze
•  Wszyscy tak robią
•  Odbicie kodu produkcyjnego
Niewłaściwe wykorzystanie
narzędzi
Przykład początkowy
@Test
public void testShouldWork() {
assertTrue(validator.isValid(
dateTime("2015-02-19 15:00"),
dateTime("2015-02-20 15:00")));
}
Zmiana nazwy
@Test
public void shouldBeValidWhenStartDateIsBeforeEndDate() {
assertTrue(validator.isValid(
dateTime("2015-02-19 15:00"),
dateTime("2015-02-20 15:00")));
}
Struktura testu
@Test
public void shouldBeValidWhenStartDateIsBeforeEndDate() {
DateTime startDate = dateTime("2015-02-19 15:00");
DateTime endDate = dateTime("2015-02-20 15:00");
boolean valid = validator.isValid(startDate, endDate);
assertTrue(valid);
}
Given / When / Then
@Test
public void shouldBeValidWhenStartDateIsBeforeEndDate() {
// given
DateTime startDate = dateTime("2015-02-19 15:00");
DateTime endDate = dateTime("2015-02-20 15:00");
// when
boolean result = validator.isValid(startDate, endDate);
// then
assertTrue(result);
}
✓
Inicjalizacja zmiennych
User user = new User();
user.setId(1);
user.setEnabled(true);
user.setFirstName("Jan");
user.setLastName("Kowalski");
Address address = new Address();
address.setCity("Gliwice");
address.setStreet("Akademicka");
address.setNumber(16);
user.setAddress(address);
// albo
User user = new User(1, true, "Jan", "Kowalski", new
Address("Gliwice" , "Akademicka", 16));
Buildery
User user = UserBuilder.anUser()
.withId(1)
.enabled()
.withFirstName("Jan")
.withLastName("Kowalski")
.livesIn(AddressBuilder.anAddress()
.inCity("Gliwice")
.onStreet("Akademicka")
.atNumber(16).build()
).build();
✓
Asercje
assertThat(user.getId()).isEqualTo(1);
assertThat(user.isEnabled()).isTrue();
assertThat(user.getFirstName()).isEqualTo("Jan");
assertThat(user.getLastName()).isEqualTo("Kowalski");
assertThat(user.getAddress().getCity()).isEqualTo("Gliwice");
assertThat(user.getAddress().getStreet()).isEqualTo("Akademicka");
assertThat(user.getAddress().getNumber()).isEqualTo(16);
Asercje domenowe
assertUser(user)
.hasId(1)
.isEnabled()
.hasFullName("Jan", "Kowalski");
assertAddress(user.getAddress())
.hasCity("Gliwice")
.hasStreet("Akademicka")
.hasNumber(16);
✓
Płynne asercje
assertThat("Quality Excites").startsWith("Quality");
assertThat("Quality Excites").containsIgnoringCase("excites");
assertThat(Math.PI).isCloseTo(3.14, within(0.002));
LocalDateTime qeDate =
LocalDateTime.parse("2015-05-30T00:00:00");
assertThat(qeDate).isAfter("1999-12-31T23:59:59");
assertThat(qeDate).matches(date ->
date.getDayOfWeek() == DayOfWeek.SATURDAY);
✓
Pętle
@Test
public void shouldBeValidWhenStartDateIsBeforeEndDate() {
// given
LocalDateTime endDate = dateTime("2015-02-20 15:00");
for (int i = 16; i <= 19; i++) {
LocalDateTime startDate = dateTime("2015-02-" + i + " 15:00");
// when
boolean result = validator.isValid(startDate, endDate);
// then
assertTrue(result);
}
}
Data-Driven Tests
@Test
@Parameters(method="nullDates")
public void shouldBeValidWhenAnyDateIsNull(
DateTime startDate, DateTime endDate) {
// when
boolean result = validator.isValid(startDate, endDate);
// then
assertTrue(result);
}
private Object nullDates() {
return $($(null, dateTime("2015-02-19 15:00")),
$(dateTime("2015-02-19 15:00"), null),
$(null, null));
}
Spock
def "be valid when any of dates is null"() {
expect:
validator.isValid(startDate, endDate)
where:
startDate | endDate
null | null
dateTime("2015-02-20 15:00") | null
null | dateTime("2015-02-20 15:00")
}
✓
Mocki
public void shouldFilterOutDeletedItems() {
// given
Item deleted = ItemBuilder.withId(1).deleted().build();
Item active = ItemBuilder.withId(2).build();
when(itemsRepository.getAllItems()).thenReturn(
newArrayList(deleted, active));
// when
List<Item> activeItems =
itemsService.getActiveItems();
// then
assertThat(activeItems).containsExactly(active);
}
✓
Nowoczesna skrzynka narzędziowa
•  Given/when/then
•  Data-driven tests
•  Buildery
•  Asercje domenowe
•  Fluent assertions
•  Mocki
•  Testowanie wyjątków
•  Testowanie asynchroniczności
•  Mocki dla REST API
Testowanie interakcji,
a nie zachowania
Then
…
verify(discountValidator).isValid(discount);
verify(userValidator).isValid(userId, discount);
verify(userRepository).getById(userId);
verify(itemsRepository).findItems(user);
verify(itemsRepository, times(2)).save(any(Item.class));
verify(discountApplier).apply(discount, item1);
verify(discountApplier).apply(discount, item2);
verifyNoMoreInteractions(userRepository);
verifyNoMoreInteractions(discountApplier);
Given / When
…
when(discountValidator.isValid(discount))
.thenReturn(true);
when(userValidator.isValid(userId, discount))
.thenReturn(true);
when(userRepository.getById(userId))
.thenReturn(user);
when(itemsRepository.findItems(user))
.thenReturn(Lists.newArrayList(item1, item2));
// then
discountService.applyDiscount(userId, discount);
…
Given
Discount discount = null;
int userId = 0;
User user = null;
Item item1 = new Item(user, 0);
Item item2 = mock(Item.class);
…
Przewaga testów integracyjnych
•  Są krótsze
•  Odporne na zmiany w implementacji
•  Sprawdzają rzeczywistość
•  Pozwalają na eksperymenty
Test integracyjny
// given
Discount discount = new Discount(20);
User user = UserBuilder.withId(123).build();
Item item1 = ItemBuilder.withId(1).soldByUser(user).withPrice(100).build();
Item item2 = ItemBuilder.withId(2).soldByUser(user).withPrice(200).build();
userRepository.save(user);
itemsRepository.saveAll(item1, item2);
// when
discountService.applyDiscount(user.getId(), discount);
// then
assertThat(itemsRepository.findItems(user))
.extracting("price").containsExactly(80, 160);
Don’t mock what
you don’t own
Serializacja
verify(mockWriter, times(1)).writeStartElement("doc");
verify(mockWriter, times(5)).writeStartElement("field");
verify(mockWriter, times(1)).writeAttribute("name", "id");
verify(mockWriter, times(1)).writeAttribute("name", "product_id");
verify(mockWriter, times(1)).writeAttribute("name", "name");
verify(mockWriter, times(5)).writeCharacters(anyString());
verify(mockWriter, times(6)).writeEndElement();
verify(mockWriter, times(1)).flush();
Mockowanie bazy danych
// given
ResultSet resultSet = mock(ResultSet.class);
when(session.execute(any(Select.Where.class)))
.thenReturn(resultSet);
Row row = mock(Row.class);
when(resultSet.all()).thenReturn(newArrayList(row));
when(row.getInt(anyString())).thenReturn(0, 123, 0);
// when
Collection<Item> items =
itemsRepository.findItems(UserBuilder.withId(1).build());
// then
assertThat(items).extracting("id").containsExactly(123);
Definicja tabeli
CREATE TABLE test.items (
user_id INT,
item_id INT,
price DECIMAL,
PRIMARY KEY(user_id)
)
Test integracyjny
// given
session.execute(
"insert into items(user_id, item_id, price) values (1, 123, 0)");
session.execute(
"insert into items(user_id, item_id, price) values (1, 124, 0)");
session.execute(
"insert into items(user_id, item_id, price) values (2, 777, 0)");
// when
Collection<Item> items =
itemsRepository.findItems(UserBuilder.withId(1).build());
// then
assertThat(items).extracting("id").containsExactly(123, 124);
✓
Testy REST API
// given
WebTarget webTargetMock = mock(WebTarget.class);
Invocation.Builder builderMock = mock(Invocation.Builder.class);
Invocation invocationMock = mock(Invocation.class);
when(clientMock.target("http://localhost:8080/items/1/price"))
.thenReturn(webTargetMock);
when(webTargetMock.request()).thenReturn(builderMock);
when(builderMock.accept(MediaType.TEXT_PLAIN)).thenReturn(builderMock);
when(builderMock.buildPost(any(Entity.class))).thenReturn(invocationMock);
// when
notifyService.updatePrice(1, 50);
// then
verify(invocationMock).submit();
WireMock
// when
notifyService.updatePrice(1, 50);
// then
verify(postRequestedFor(urlEqualTo("/items/1/price"))
.withRequestBody(equalToJson("{"price": 50}"))
.withHeader(HttpHeaders.ACCEPT, equalTo("text/plain")));
✓
Podsumowanie
•  Czysty kod się liczy
•  Im mniej kodu tym lepiej
•  No silver bullets
Q/A?
Thank you!
Check us: allegrotech.io
Join us: kariera.allegro.pl
Twitter: allegrotechblog
e-commerce full of technology
github.com/msulima/tests-showcase

Contenu connexe

En vedette

Albert michelson michelle calderon
Albert  michelson michelle calderonAlbert  michelson michelle calderon
Albert michelson michelle calderon
britney8sapphire
 
العرض
العرضالعرض
العرض
hadeel88
 
العرض
العرضالعرض
العرض
hadeel88
 
العرض
العرضالعرض
العرض
hadeel88
 
Quality report 10 2013
Quality report 10 2013Quality report 10 2013
Quality report 10 2013
kortneybrad
 
العرض
العرضالعرض
العرض
hadeel88
 
العرض
العرضالعرض
العرض
hadeel88
 
Galileo galiliei by daniela garcia
Galileo galiliei by daniela garciaGalileo galiliei by daniela garcia
Galileo galiliei by daniela garcia
dgarcia0662
 

En vedette (20)

Wyzwania i odpowiedzialność projektanta/WUD Silesia 2014
Wyzwania i odpowiedzialność projektanta/WUD Silesia 2014Wyzwania i odpowiedzialność projektanta/WUD Silesia 2014
Wyzwania i odpowiedzialność projektanta/WUD Silesia 2014
 
Albert michelson michelle calderon
Albert  michelson michelle calderonAlbert  michelson michelle calderon
Albert michelson michelle calderon
 
[QE 2015] Sam Elamin - Monoliths to microservices - a journey
[QE 2015] Sam Elamin - Monoliths to microservices - a journey[QE 2015] Sam Elamin - Monoliths to microservices - a journey
[QE 2015] Sam Elamin - Monoliths to microservices - a journey
 
العرض
العرضالعرض
العرض
 
العرض
العرضالعرض
العرض
 
[FDD 2016] Krzysztof Jendrzyca - Funkcyjny Frontend
[FDD 2016] Krzysztof Jendrzyca - Funkcyjny Frontend[FDD 2016] Krzysztof Jendrzyca - Funkcyjny Frontend
[FDD 2016] Krzysztof Jendrzyca - Funkcyjny Frontend
 
Find out more about LearnUpon's LMS and what it can do for you
Find out more about LearnUpon's LMS and what it can do for youFind out more about LearnUpon's LMS and what it can do for you
Find out more about LearnUpon's LMS and what it can do for you
 
العرض
العرضالعرض
العرض
 
[QE 2015] Grzegorz Gałęzowski - Projektowanie kompozycjonalne – po co (tak na...
[QE 2015] Grzegorz Gałęzowski - Projektowanie kompozycjonalne – po co (tak na...[QE 2015] Grzegorz Gałęzowski - Projektowanie kompozycjonalne – po co (tak na...
[QE 2015] Grzegorz Gałęzowski - Projektowanie kompozycjonalne – po co (tak na...
 
[QE 2015] Marcin Budny, Ryszard Tarajkowski - Testy łatwe w utrzymaniu
[QE 2015] Marcin Budny, Ryszard Tarajkowski - Testy łatwe w utrzymaniu[QE 2015] Marcin Budny, Ryszard Tarajkowski - Testy łatwe w utrzymaniu
[QE 2015] Marcin Budny, Ryszard Tarajkowski - Testy łatwe w utrzymaniu
 
[Quality Meetup #9] Testowanie w świecie ontologii - A. Ostaszewska-Smykała, ...
[Quality Meetup #9] Testowanie w świecie ontologii - A. Ostaszewska-Smykała, ...[Quality Meetup #9] Testowanie w świecie ontologii - A. Ostaszewska-Smykała, ...
[Quality Meetup #9] Testowanie w świecie ontologii - A. Ostaszewska-Smykała, ...
 
[FDD 2016] Katarzyna Bremer - BIML - sterowane metadanymi tworzenie pakietów ...
[FDD 2016] Katarzyna Bremer - BIML - sterowane metadanymi tworzenie pakietów ...[FDD 2016] Katarzyna Bremer - BIML - sterowane metadanymi tworzenie pakietów ...
[FDD 2016] Katarzyna Bremer - BIML - sterowane metadanymi tworzenie pakietów ...
 
Quality report 10 2013
Quality report 10 2013Quality report 10 2013
Quality report 10 2013
 
New microsoft office power point presentation (3)
New microsoft office power point presentation (3)New microsoft office power point presentation (3)
New microsoft office power point presentation (3)
 
Jenkins – przyjaciel każdego testera.
Jenkins – przyjaciel każdego testera.Jenkins – przyjaciel każdego testera.
Jenkins – przyjaciel każdego testera.
 
العرض
العرضالعرض
العرض
 
العرض
العرضالعرض
العرض
 
[QE 2015] Krystian Kaczor - Wymagania w Agile
[QE 2015] Krystian Kaczor - Wymagania w Agile[QE 2015] Krystian Kaczor - Wymagania w Agile
[QE 2015] Krystian Kaczor - Wymagania w Agile
 
Galileo galiliei by daniela garcia
Galileo galiliei by daniela garciaGalileo galiliei by daniela garcia
Galileo galiliei by daniela garcia
 
[FDD 2016] Kamil Dworak - Przetwarzanie danych pomiarowych w tle z wykorzysta...
[FDD 2016] Kamil Dworak - Przetwarzanie danych pomiarowych w tle z wykorzysta...[FDD 2016] Kamil Dworak - Przetwarzanie danych pomiarowych w tle z wykorzysta...
[FDD 2016] Kamil Dworak - Przetwarzanie danych pomiarowych w tle z wykorzysta...
 

Plus de Future Processing

Plus de Future Processing (20)

DPTO_Inżynieria oprogramowania to proces uczenia się.pdf
DPTO_Inżynieria oprogramowania to proces uczenia się.pdfDPTO_Inżynieria oprogramowania to proces uczenia się.pdf
DPTO_Inżynieria oprogramowania to proces uczenia się.pdf
 
DPTO_QA w świecie wartości biznesowych.pdf
DPTO_QA w świecie wartości biznesowych.pdfDPTO_QA w świecie wartości biznesowych.pdf
DPTO_QA w świecie wartości biznesowych.pdf
 
DPTO_Hello_Clean_Architekture.pdf
DPTO_Hello_Clean_Architekture.pdfDPTO_Hello_Clean_Architekture.pdf
DPTO_Hello_Clean_Architekture.pdf
 
[Quality Meetup #20] Michał Górski - Continuous Deployment w chmurze
[Quality Meetup #20] Michał Górski - Continuous Deployment w chmurze[Quality Meetup #20] Michał Górski - Continuous Deployment w chmurze
[Quality Meetup #20] Michał Górski - Continuous Deployment w chmurze
 
[Quality Meetup #20] Dorota Tadych - Hyperion - wystarczy jeden shake
[Quality Meetup #20] Dorota Tadych - Hyperion - wystarczy jeden shake[Quality Meetup #20] Dorota Tadych - Hyperion - wystarczy jeden shake
[Quality Meetup #20] Dorota Tadych - Hyperion - wystarczy jeden shake
 
[Quality Meetup #19] Magdalena Drechsler-Nowak - Tester w pułapce myślenia
[Quality Meetup #19] Magdalena Drechsler-Nowak - Tester w pułapce myślenia[Quality Meetup #19] Magdalena Drechsler-Nowak - Tester w pułapce myślenia
[Quality Meetup #19] Magdalena Drechsler-Nowak - Tester w pułapce myślenia
 
[Quality Meetup #19] Adrian Gonciarz - Testerska ruletka
[Quality Meetup #19] Adrian Gonciarz - Testerska ruletka[Quality Meetup #19] Adrian Gonciarz - Testerska ruletka
[Quality Meetup #19] Adrian Gonciarz - Testerska ruletka
 
[FDD 2018] Krzysztof Sikora - Jak Service Fabric rozwiąże twoje problemy z mi...
[FDD 2018] Krzysztof Sikora - Jak Service Fabric rozwiąże twoje problemy z mi...[FDD 2018] Krzysztof Sikora - Jak Service Fabric rozwiąże twoje problemy z mi...
[FDD 2018] Krzysztof Sikora - Jak Service Fabric rozwiąże twoje problemy z mi...
 
[FDD 2018] Ł. Turchan, A. Hulist, M. Duchnowski - CUDA - results over coffee ...
[FDD 2018] Ł. Turchan, A. Hulist, M. Duchnowski - CUDA - results over coffee ...[FDD 2018] Ł. Turchan, A. Hulist, M. Duchnowski - CUDA - results over coffee ...
[FDD 2018] Ł. Turchan, A. Hulist, M. Duchnowski - CUDA - results over coffee ...
 
[FDD 2018] Lech Kalinowski - Prywatny Blockchain
[FDD 2018] Lech Kalinowski - Prywatny Blockchain[FDD 2018] Lech Kalinowski - Prywatny Blockchain
[FDD 2018] Lech Kalinowski - Prywatny Blockchain
 
[FDD 2018] W. Malara, K. Kotowski - Autoenkodery – czyli zalety funkcji F(X)≈X
[FDD 2018] W. Malara, K. Kotowski - Autoenkodery – czyli zalety funkcji F(X)≈X[FDD 2018] W. Malara, K. Kotowski - Autoenkodery – czyli zalety funkcji F(X)≈X
[FDD 2018] W. Malara, K. Kotowski - Autoenkodery – czyli zalety funkcji F(X)≈X
 
[FDD 2018] Jarosław Ogiegło - Ludzie, zabezpieczajcie się! Wprowadzenie do OA...
[FDD 2018] Jarosław Ogiegło - Ludzie, zabezpieczajcie się! Wprowadzenie do OA...[FDD 2018] Jarosław Ogiegło - Ludzie, zabezpieczajcie się! Wprowadzenie do OA...
[FDD 2018] Jarosław Ogiegło - Ludzie, zabezpieczajcie się! Wprowadzenie do OA...
 
[JuraSIC! Meetup] Krzysztof Sikora- Jak Service Fabric rozwiąże twoje problem...
[JuraSIC! Meetup] Krzysztof Sikora- Jak Service Fabric rozwiąże twoje problem...[JuraSIC! Meetup] Krzysztof Sikora- Jak Service Fabric rozwiąże twoje problem...
[JuraSIC! Meetup] Krzysztof Sikora- Jak Service Fabric rozwiąże twoje problem...
 
[JuraSIC! Meetup] Mateusz Stasch - Monady w .NET
[JuraSIC! Meetup] Mateusz Stasch - Monady w .NET[JuraSIC! Meetup] Mateusz Stasch - Monady w .NET
[JuraSIC! Meetup] Mateusz Stasch - Monady w .NET
 
[QE 2018] Aleksandra Kornecka – Kognitywne podejście do testowania aplikacji ...
[QE 2018] Aleksandra Kornecka – Kognitywne podejście do testowania aplikacji ...[QE 2018] Aleksandra Kornecka – Kognitywne podejście do testowania aplikacji ...
[QE 2018] Aleksandra Kornecka – Kognitywne podejście do testowania aplikacji ...
 
[QE 2018] Adam Stasiak – Nadchodzi React Native – czyli o testowaniu mobilnyc...
[QE 2018] Adam Stasiak – Nadchodzi React Native – czyli o testowaniu mobilnyc...[QE 2018] Adam Stasiak – Nadchodzi React Native – czyli o testowaniu mobilnyc...
[QE 2018] Adam Stasiak – Nadchodzi React Native – czyli o testowaniu mobilnyc...
 
[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark Applications
[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark Applications[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark Applications
[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark Applications
 
[QE 2018] Marek Puchalski – Web Application Security Test Automation
[QE 2018] Marek Puchalski – Web Application Security Test Automation[QE 2018] Marek Puchalski – Web Application Security Test Automation
[QE 2018] Marek Puchalski – Web Application Security Test Automation
 
[QE 2018] Rob Lambert – How to Thrive as a Software Tester
[QE 2018] Rob Lambert – How to Thrive as a Software Tester[QE 2018] Rob Lambert – How to Thrive as a Software Tester
[QE 2018] Rob Lambert – How to Thrive as a Software Tester
 
[QE 2018] Paul Gerrard – Automating Assurance: Tools, Collaboration and DevOps
[QE 2018] Paul Gerrard – Automating Assurance: Tools, Collaboration and DevOps[QE 2018] Paul Gerrard – Automating Assurance: Tools, Collaboration and DevOps
[QE 2018] Paul Gerrard – Automating Assurance: Tools, Collaboration and DevOps
 

[QE 2015] Mateusz Sulima - Kręta droga do dobrych testów