{"id":10899,"date":"2021-07-07T23:32:58","date_gmt":"2021-07-07T21:32:58","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=10899"},"modified":"2023-10-27T17:40:50","modified_gmt":"2023-10-27T15:40:50","slug":"abap-unit-i-test-driven-development","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/abap-unit-i-test-driven-development\/","title":{"rendered":"ABAP Unit i Test-driven Development"},"content":{"rendered":"\n<p>Zmiany wprowadzane w tradycyjnych programach cz\u0119sto psuj\u0105 ich funkcjonalno\u015b\u0107, powoduj\u0105c przy tym ogromne szkody w dzia\u0142alno\u015bci ca\u0142ego systemu. <\/p>\n\n\n\n<p>Chc\u0105c unikn\u0105\u0107 takiej sytuacji, nale\u017cy wykorzystywa\u0107 rozw\u00f3j oparty na testach (TDD \u2013 ang. Test-driven Development) dzi\u0119ki narz\u0119dziu ABAP Unit. W tym artykule wyja\u015bni\u0119, czym jest TDD i jak je wdro\u017cy\u0107 w ABAP-ie.<\/p>\n\n\n\n<p>W tradycyjnym procesie programistycznym po stworzeniu nowego programu lub zmianie istniej\u0105cego nast\u0119pnym krokiem jest wykonanie podstawowych test\u00f3w. W rzeczywisto\u015bci jednak cz\u0119sto brakuje czasu na ten etap prac i jest on pomijany, cz\u0119sto z katastrofalnymi skutkami. Przeciwie\u0144stwem takiego procesu jest TDD, polegaj\u0105cy na pisaniu test\u00f3w przed utworzeniem nowej funkcjonalno\u015bci b\u0105d\u017a zmiany istniej\u0105cej.<\/p>\n\n\n\n<p>W artykule skupi\u0119 si\u0119 na dzia\u0142aniu framework\u2019a ABAP Unit i na tym, jak dodawa\u0107 testy jednostkowe do istniej\u0105cego kodu, czy to proceduralnego czy obiektowego. Programi\u015bci, kt\u00f3rzy pisz\u0105 nowy kod lub tworz\u0105 zmiany w kodzie istniej\u0105cym, powinni zacz\u0105\u0107 swoj\u0105 prac\u0119 od napisania testu jednostkowego przed dokonaniem zmian w kodzie. Mo\u017ce to si\u0119 wydawa\u0107 dziwne, poniewa\u017c tworzysz test jednostkowy do kodu, kt\u00f3ry jeszcze nie istnieje. Ale o to w\u0142a\u015bnie chodzi. Najpierw udowadniasz, \u017ce napisany kod nie robi tego co tak naprawd\u0119 powinien, poprzez napisanie testu jednostkowego. Nast\u0119pnie tworzysz kod, a\u017c w 100% b\u0119dziesz pewny, \u017ce problem zosta\u0142 rozwi\u0105zany.<\/p>\n\n\n\n<p>W normalnym procesie developmentu piszesz kod, aby rozwi\u0105za\u0107 problem i dop\u00f3ki nie zrobisz testu r\u0119cznego, nie jeste\u015b w 100% pewien czy napisa\u0142e\u015b kod poprawnie, czy te\u017c nie. TDD zapobiega takiej sytuacji przebiegaj\u0105c wed\u0142ug okre\u015blonego cyklu:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Napisanie przypadku testowego.<br><\/strong>Na tym etapie powinni\u015bmy wiedzie\u0107, co chcemy przetestowa\u0107 i czego oczekujemy od testowanego funkcjonalno\u015bci.<\/li>\n\n\n\n<li><strong>Uruchomienie napisanego testu.<br><\/strong>Uruchomienie testu i oczekiwanie na b\u0142\u0105d kompilacji, poniewa\u017c nie istnieje kod, kt\u00f3ry chcemy testowa\u0107.<\/li>\n\n\n\n<li><strong>Napisanie minimalnego kodu.<br><\/strong>Stworzenie minimalnego kodu odpowiedzialnego za funkcjonalno\u015b\u0107, dzi\u0119ki kt\u00f3remu po uruchomieniu testu przejdzie w stan \u201ezielony\u201d.<\/li>\n\n\n\n<li><strong>Refaktoryzacja napisanego kodu.<br><\/strong>Przeprowadzamy refaktoryzacj\u0119 kodu produkcyjnego i kodu testowego.<\/li>\n\n\n\n<li><strong>Uruchomienie wszystkich test\u00f3w.<br><\/strong>Cykl TDD si\u0119 zamyka i powtarzamy go, dop\u00f3ki nie napiszemy wszystkich test\u00f3w pokrywaj\u0105cych logik\u0119 biznesow\u0105.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Definicja klasy testowej<\/h2>\n\n\n\n<p>Aby zdefiniowa\u0107 klas\u0119 testow\u0105, musisz najpierw mie\u0107 zdefiniowan\u0105 klas\u0119 globaln\u0105, u\u017cywaj\u0105c do tego transakcji SE24 albo SE80. Po stworzeniu klasy globalnej przejd\u017a do menu: <strong>Skok do \u2192 Lokalne definicje\/implementacje \u2192 Lokalne klasy testowe <\/strong>(z ang. Goto <strong> \u2192 <\/strong> Local Definitions\/Implementations<strong> \u2192 <\/strong>Local Test Class).<\/p>\n\n\n\n<p>W klasie testowej musisz zdefiniowa\u0107 kilka rzeczy:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>W\u0142\u0105czenie testowania prywatnych metod.<\/li>\n\n\n\n<li>Ustalenie og\u00f3lnych ustawie\u0144 definicji klasy testowej.<\/li>\n\n\n\n<li>Deklaracja definicji danych.<\/li>\n\n\n\n<li>Konfiguracja test\u00f3w jednostkowych.<\/li>\n\n\n\n<li>Definicja rzeczywistych metod testowania.<\/li>\n\n\n\n<li>Implementacja metod pomocniczych.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">W\u0142\u0105czenie testowania prywatnych metod<\/h2>\n\n\n\n<p>Aby w\u0142\u0105czy\u0107 testowanie prywatnych metod nale\u017cy doda\u0107 nast\u0119puj\u0105cy kod:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter wp-image-10902 size-full\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/W\u0142\u0105czenie-testowania-prywatnych-metod.png\"><img decoding=\"async\" width=\"717\" height=\"99\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/W\u0142\u0105czenie-testowania-prywatnych-metod.png\" alt=\"fragment kodu\" class=\"wp-image-10902\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/W\u0142\u0105czenie-testowania-prywatnych-metod.png 717w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/W\u0142\u0105czenie-testowania-prywatnych-metod-300x41.png 300w\" sizes=\"(max-width: 717px) 100vw, 717px\" \/><\/a><\/figure>\n\n\n\n<p>W powy\u017cszym przyk\u0142adzie klasa <strong>ZCL_RANGE<\/strong> jest klas\u0105 globaln\u0105, kt\u00f3r\u0105 b\u0119dzie testowana przez lokaln\u0105 klas\u0119 <strong>LCL_RANGE_TEST_CLASS. <\/strong>W\u0142\u0105czenie funkcjonalno\u015bci testowania metod prywatnych odbywa si\u0119 za po\u015brednictwem s\u0142\u00f3w kluczowych <strong>LOCAL FRIENDS<\/strong> <strong><em>nazwa_klasy_testowej<\/em><\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Ustalenie og\u00f3lnych ustawie\u0144 definicji klasy testowej<\/h2>\n\n\n\n<p>Pierwsza linijka m\u00f3wi, \u017ce jest to klasa testowa. Nast\u0119pnie definiujemy RISK LEVEL (poziom ryzyka) \u2013 rozr\u00f3\u017cniane<br>s\u0105 trzy: CRITICAL, DANGEROUS i HARMLESS. Ostatni\u0105 w\u0142a\u015bciwo\u015bci\u0105 jest DURATION (czas trwania testu), gdzie do wyboru s\u0105 trzy poziomy: LONG, MEDIUM oraz SHORT.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Ustalenie-og\u00f3lnych-ustawie\u0144-definicji-klasy-testowej.png\"><img decoding=\"async\" width=\"594\" height=\"128\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Ustalenie-og\u00f3lnych-ustawie\u0144-definicji-klasy-testowej.png\" alt=\"fragment kodu\" class=\"wp-image-10911\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Ustalenie-og\u00f3lnych-ustawie\u0144-definicji-klasy-testowej.png 594w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Ustalenie-og\u00f3lnych-ustawie\u0144-definicji-klasy-testowej-300x65.png 300w\" sizes=\"(max-width: 594px) 100vw, 594px\" \/><\/a><\/figure>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Deklaracja definicji danych<\/h2>\n\n\n\n<p>Kontynuuj\u0105c definicj\u0119 klasy testowej dochodzimy do deklaracji danych. Pierwsz\u0105 i najwa\u017cniejsz\u0105 zmienn\u0105 jak\u0105 deklarujemy jest zmienna do przechowywania instancji klasy, kt\u00f3ra jest testowana.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Deklaracja-definicji-danych.png\"><img decoding=\"async\" width=\"608\" height=\"224\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Deklaracja-definicji-danych.png\" alt=\"fragment kodu\" class=\"wp-image-10904\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Deklaracja-definicji-danych.png 608w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Deklaracja-definicji-danych-300x111.png 300w\" sizes=\"(max-width: 608px) 100vw, 608px\" \/><\/a><\/figure>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Definicja metody SETUP<\/h2>\n\n\n\n<p>Pierwsz\u0105 metod\u0105, kt\u00f3r\u0105 nale\u017cy zawsze zdefiniowa\u0107 jest prywatna metoda <strong>SETUP<\/strong>. Odpowiedzialna jest za resetowanie stanu systemu, tak aby ka\u017cda metoda testowa zachowywa\u0142a si\u0119 jakby by\u0142a pierwsz\u0105 uruchomion\u0105 metod\u0105 testow\u0105. Dlatego ka\u017cda z globalnych zmiennych musi zosta\u0107 wyczyszczona lub ustawiona na okre\u015blon\u0105 warto\u015b\u0107, a testowana klasa musi zosta\u0107 utworzona od nowa. Pozwala to unikn\u0105\u0107 tzw. sprz\u0119\u017cenia czasowego (wynik jednego testu mo\u017ce mie\u0107 wp\u0142yw na wynik drugiego testu).<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Definicja-metody-SETUP.png\"><img decoding=\"async\" width=\"864\" height=\"447\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Definicja-metody-SETUP.png\" alt=\"fragment kodu\" class=\"wp-image-10913\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Definicja-metody-SETUP.png 864w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Definicja-metody-SETUP-300x155.png 300w\" sizes=\"(max-width: 864px) 100vw, 864px\" \/><\/a><\/figure>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Definicja rzeczywistych metod testowania<\/h2>\n\n\n\n<p>Po definicji metody SETUP nast\u0119pnym krokiem jest definicja rzeczywistych metod testowania. S\u0142owa kluczowe <strong>FOR TESTING<\/strong> po nazwie metody informuj\u0105, \u017ce ta metoda b\u0119dzie uruchamiana za ka\u017cdym razem, kiedy programista uruchomi test.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Definicja-rzeczywistych-metod-testowania.png\"><img decoding=\"async\" width=\"699\" height=\"344\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Definicja-rzeczywistych-metod-testowania.png\" alt=\"fragment kodu\" class=\"wp-image-10903\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Definicja-rzeczywistych-metod-testowania.png 699w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Definicja-rzeczywistych-metod-testowania-300x148.png 300w\" sizes=\"(max-width: 699px) 100vw, 699px\" \/><\/a><\/figure>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Implementacja metod pomocniczych<\/h2>\n\n\n\n<p>Ostatnim krokiem jest implementacja metod pomocniczych (bez s\u0142\u00f3w kluczowych <strong>FOR TESTING<\/strong>).<br>S\u0105 to zwyczajne metody prywatne wywo\u0142ywane przez metody testowe. Celem metod pomocniczych jest wykonanie zada\u0144 ni\u017cszego poziomu dla jednej lub wi\u0119cej metod testowych.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-metod-pomocniczych.png\"><img decoding=\"async\" width=\"741\" height=\"465\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-metod-pomocniczych.png\" alt=\"fragment kodu\" class=\"wp-image-10906\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-metod-pomocniczych.png 741w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-metod-pomocniczych-300x188.png 300w\" sizes=\"(max-width: 741px) 100vw, 741px\" \/><\/a><\/figure>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-metod-pomocniczych-cd.png\"><img decoding=\"async\" width=\"941\" height=\"479\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-metod-pomocniczych-cd.png\" alt=\"fragment kodu\" class=\"wp-image-10905\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-metod-pomocniczych-cd.png 941w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-metod-pomocniczych-cd-300x153.png 300w\" sizes=\"(max-width: 941px) 100vw, 941px\" \/><\/a><\/figure>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Struktura GIVEN\/WHEN\/THEN<\/h2>\n\n\n\n<p>Kod metody testuj\u0105cej powinien by\u0107 napisany we wzorcu GIVEN\/WHEN\/THEN. GIVEN opisuje stan tu\u017c przed testem, kt\u00f3ry ma zosta\u0107 wykonany. W tej sekcji r\u00f3wnie\u017c okre\u015blane s\u0105 parametry wej\u015bciowe testu. W sekcji WHEN testowana jest funkcjonalno\u015b\u0107. W ostatniej cz\u0119\u015bci THEN sprawdzane s\u0105 warunki (wywo\u0142ywane metody ASSERT).<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Struktura-GIVEN_WHEN_THEN.png\"><img decoding=\"async\" width=\"694\" height=\"384\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Struktura-GIVEN_WHEN_THEN.png\" alt=\"fragment kodu\" class=\"wp-image-10909\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Struktura-GIVEN_WHEN_THEN.png 694w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Struktura-GIVEN_WHEN_THEN-300x166.png 300w\" sizes=\"(max-width: 694px) 100vw, 694px\" \/><\/a><\/figure>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Test Doubles<\/h2>\n\n\n\n<p>Za\u0142o\u017ceniem Test Doubles jest podmieni\u0107 w trakcie trwania test\u00f3w zale\u017cno\u015bci testowanej klasy czym\u015b, nad czym mamy pe\u0142n\u0105 kontrol\u0119. Warto zdecydowa\u0107 si\u0119 na taki manewr w momencie, gdy nie mo\u017cemy (albo z jaki\u015b powod\u00f3w nie chcemy) skorzysta\u0107 z prawdziwych zale\u017cno\u015bci (w obiekcie zale\u017cnym \u201edu\u017co si\u0119 dzieje\u201d\/posiada skomplikowan\u0105 logik\u0119). Tak naprawd\u0119 te zale\u017cno\u015bci s\u0105 w rzeczywisto\u015bci nieszkodliwymi duplikatami wykorzystywanymi tylko i wy\u0142\u0105cznie do cel\u00f3w testowych.<\/p>\n\n\n\n<p>Kiedy m\u00f3wimy o testowaniu podw\u00f3jnym u\u017cywamy termin\u00f3w: stub, spy, mock object, dummy object, fake object. S\u0105 to rodzaje Test Doubles, kt\u00f3re s\u0105 wykorzystywane w zale\u017cno\u015bci od potrzeb.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Stub<\/strong> \u2013 wykorzystywany jest w sytuacji, kiedy obiekt klasy testowej jest zale\u017cny od zwracanych parametr\u00f3w przez metod\u0119 obiektu dublowanego.<\/li>\n\n\n\n<li><strong>Spy<\/strong> \u2013 wykorzystywany jest w sytuacji, kiedy chcemy mie\u0107 pewno\u015b\u0107, \u017ce dana metoda innego obiektu zosta\u0142a wywo\u0142ana przez klas\u0119 testow\u0105 z oczekiwanymi parametrami, nie spodziewaj\u0105c si\u0119 odpowiedzi. Jest to tzw. punkt obserwacyjny, kt\u00f3ry weryfikuje nasze za\u0142o\u017cenia.<\/li>\n\n\n\n<li><strong>Mock Object<\/strong> \u2013 wykorzystujemy ten typ, gdy zale\u017cy nam na konkretnej odpowiedzi w przypadku otrzymania konkretnych warto\u015bci.<\/li>\n\n\n\n<li><strong>Fake Object<\/strong> \u2013 dublowane obiekty, kt\u00f3re zawieraj\u0105 mniej skomplikowana logik\u0119 biznesow\u0105 w por\u00f3wnaniu do oryginalnych obiekt\u00f3w.<\/li>\n\n\n\n<li><strong>Dummy Object<\/strong> \u2013 wykorzystywane w sytuacji, kiedy chcemy przekaza\u0107 sam\u0105 instancj\u0119 obiektu.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Implementacja Test Doubles<\/h2>\n\n\n\n<p>Na potrzeby przyk\u0142adu stworzy\u0142em dwie klasy oraz jeden interfejs, kt\u00f3ry jest odpowiedzialny za pobieranie aktualnego kursu walut. U\u017cytkownik podaje walut\u0119 \u017ar\u00f3d\u0142owa i docelow\u0105, a interfejs zwraca odpowiedni kurs. Pierwsza klasa jest odwzorowaniem banknotu. Zawiera w sobie dwa atrybuty <strong>AMOUNT<\/strong> i <strong>CURRENCY<\/strong> oraz metody GET dla tych atrybut\u00f3w. Druga klasa jest odwzorowaniem portfela. Zawiera atrybuty <strong>BANKNOTE<\/strong> i <strong>RATE_PROVIDER<\/strong> oraz metody: <strong>ADD_BANKNOTE<\/strong>, <strong>SET_RATE_PROVIDER<\/strong> oraz <strong>GET_AMOUNT<\/strong>. Stworzy\u0142em klas\u0119 testow\u0105 o nast\u0119puj\u0105cej definicji oraz implementacji.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-Test-Doubles-e1624969909662.png\"><img decoding=\"async\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-Test-Doubles.png\" alt=\"fragment kodu\" class=\"wp-image-10908\"\/><\/a><\/figure>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-Test-Doubles-cd.png\"><img decoding=\"async\" width=\"900\" height=\"420\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-Test-Doubles-cd.png\" alt=\"fragment kodu\" class=\"wp-image-10907\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-Test-Doubles-cd.png 900w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Implementacja-Test-Doubles-cd-300x140.png 300w\" sizes=\"(max-width: 900px) 100vw, 900px\" \/><\/a><\/figure>\n\n\n\n<p>Aby test klasy <strong>ZCL_DEMO_WALLET<\/strong> zosta\u0142 poprawnie napisany musia\u0142em wykorzysta\u0107 Test Doubles. Stworzy\u0142em instancj\u0119 obiektu dublowanego, kt\u00f3ry implementuje interfejs <strong>ZIF_DEMO_RATE_PROVIDER<\/strong> (linia 29). W naszym przyk\u0142adzie metod\u0105 do dublowania b\u0119dzie <strong>GET_CURRENCY_RATE<\/strong>. Mo\u017ce si\u0119 to wydawa\u0107 dziwne, ale na pocz\u0105tku nie wywo\u0142ujemy tej metody, lecz ustawiamy warto\u015b\u0107 jak\u0105 ona zwr\u00f3ci, a nast\u0119pnie jest ona wywo\u0142ywana (linie 30-33).<\/p>\n\n\n\n<p>W te\u015bcie wykorzysta\u0142em stub-a, poniewa\u017c zwracana warto\u015b\u0107 przez metod\u0119 <strong>GET_TOTAL_AMOUNT <\/strong>jest zale\u017cna od obiektu <strong>RATE_PROVIDER<\/strong>. Je\u015bli testy zosta\u0142y wykonane prawid\u0142owo, w\u00f3wczas powinny by\u0107 oznaczone na zielono. Na poni\u017cszym obrazku znajduje si\u0119 wynik testu:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Wynik-testu.png\"><img decoding=\"async\" width=\"606\" height=\"293\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Wynik-testu.png\" alt=\"\" class=\"wp-image-10912\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Wynik-testu.png 606w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Wynik-testu-300x145.png 300w\" sizes=\"(max-width: 606px) 100vw, 606px\" \/><\/a><\/figure>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Uruchamianie test\u00f3w jednostkowych<\/h2>\n\n\n\n<p>Aby uruchomi\u0107 testy jednostkowe, nale\u017cy przej\u015b\u0107 do transakcji SE80. Nast\u0119pnie nale\u017cy odnale\u017a\u0107 testowan\u0105 klas\u0119 oraz klikn\u0105\u0107 na niej PPM i wybra\u0107: <strong>Wykonanie -&gt; Testy modu\u0142owe z -&gt; Pomiar pokrycia:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><a href=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Uruchamianie-test\u00f3w-jednostkowych.png\"><img decoding=\"async\" width=\"835\" height=\"383\" src=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Uruchamianie-test\u00f3w-jednostkowych.png\" alt=\"\" class=\"wp-image-10910\" srcset=\"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Uruchamianie-test\u00f3w-jednostkowych.png 835w, https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/Uruchamianie-test\u00f3w-jednostkowych-300x138.png 300w\" sizes=\"(max-width: 835px) 100vw, 835px\" \/><\/a><\/figure>\n\n\n\n<div style=\"height:20px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Podsumowanie<\/h2>\n\n\n\n<p>Testowanie jednostkowe wcale nie jest \u0142atwe, wr\u0119cz przeciwnie. U\u017cywaj\u0105c funkcjonalno\u015bci<br>z pe\u0142nym pokryciem testowym i korzystaj\u0105c z metodologii TDD przy ich tworzeniu, mamy du\u017c\u0105 lepsz\u0105 kontrol\u0119 nad utrzymaniem i rozwojem kodu. Wprowadzaj\u0105c dowolne zmiany czy przeprowadzaj\u0105c refaktoryzacj\u0119 kodu, w ci\u0105gu kilku sekund dowiesz si\u0119, czy zepsu\u0142e\u015b jak\u0105kolwiek istniej\u0105c\u0105 funkcjonalno\u015b\u0107. Kiedy zaczniesz korzysta\u0107 z TDD, przekonasz si\u0119, \u017ce cykl ten przebiega w kilku krokach. Musisz jedynie po\u015bwi\u0119ci\u0107 troch\u0119 czasu i nabra\u0107 wprawy, a w przysz\u0142o\u015bci testy jednostkowe stan\u0105 si\u0119 nieodzownym elementem Twojej pracy.<\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;10899&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;1&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;5&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;5\\\/5 ( vote: 1)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;ABAP Unit i Test-driven Development&quot;,&quot;width&quot;:&quot;139.5&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 139.5px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            5\/5 ( vote: 1)    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>Zmiany wprowadzane w tradycyjnych programach cz\u0119sto psuj\u0105 ich funkcjonalno\u015b\u0107, powoduj\u0105c przy tym ogromne szkody w dzia\u0142alno\u015bci ca\u0142ego systemu. Chc\u0105c unikn\u0105\u0107 &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/abap-unit-i-test-driven-development\/\">Continued<\/a><\/p>\n","protected":false},"author":294,"featured_media":11004,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[860,174,811],"class_list":["post-10899","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-abap-unit","tag-erp","tag-sap-abap"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2021\/06\/grafika.png","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/10899"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/294"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=10899"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/10899\/revisions"}],"predecessor-version":[{"id":25297,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/10899\/revisions\/25297"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/11004"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=10899"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=10899"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=10899"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}