Sign in Join
Wiki copytemporary

fpcunit/pl: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: fpcunit/pl

OldNewLine
1+## Przegląd
2+
3+Fpcunit to framework do testowania modułów w stylu DUnit/JUnit/[SUnit](https://en.wikipedia.org/wiki/SUnit). Pozwala to na szybkie napisanie zestawu testów dla (logiki) kodu modułu (niekoniecznie takiego samego jak moduł Pascala, chociaż często tak jest).
4+
5+Metodologie programowania, takie jak Test Driven Design, wykorzystują to, aby upewnić się, że najpierw kodujesz swoje oczekiwania/specyfikacje w testach jednostkowych, następnie piszesz główny kod, a następnie uruchamiasz testy i ulepszasz kod, aż wszystkie testy zakończą się pomyślnie.
6+
7+fpcunit pozwala nie tylko na wizualną kontrolę przebiegów testów, ale także na systematyczne zbieranie wyników (za pomocą danych wyjściowych XML) i wykorzystanie ich do porównywania wersji m.in. błędy regresji (tzn. uruchamiasz testy regresji przy użyciu danych wyjściowych testu jednostkowego).
8+
9+Zrzut ekranu programu uruchamiającego test GUI:
10+
11+![](/wiki-images/f/f8/Guitestrunner.png)
12+
13+Powyższy obraz pokazuje, że na 10 testów, 6 testów zakończyło się niepowodzeniem. Wyjątki *EAssertionFailure* wskazują, że twierdzenia testowe (patrz poniżej) nie zostały spełnione – tj. test nie powiódł się. Powiązane komunikaty wskazują wynik oczekiwany przez test i wynik rzeczywisty osiągnięty przez test.
14+
15+## Użycie w FPC/Lazarus
16+
17+Testy FPCUnit są używane w ramach testowej bazy danych FPC: [[Databases|Databases#Running_FPC_database_tests]]
18+
19+Istnieją również testy dla pakietów kompilatora/rdzenia FPC, ale przypuszczalnie poprzedzają one fpcunit i wykorzystują prostsze podejście.
20+
21+## Użycie
22+
23+Do skonfigurowania Twojego nowego projektu testowego, najłatwiej jest użyć Lazarusa. Poniżej znajduje się kilka opisów procedur/metod, których należy użyć w takim celu.
24+
25+### Metoda SetUp
26+
27+Ta procedura jest obecna we wszystkich testach FPCUnit. Konfiguruje środowisko testowe przed uruchomieniem **każdego** testu – innymi słowy nie tylko przed i po uruchomieniu całego zestawu testów, ale dla każdego testu”. Możesz to wykorzystać m.in. do tego, aby wypełnić bazę danych danymi testowymi.
28+
29+### Metoda TearDown
30+
31+Ta procedura jest obecna we wszystkich testach FPCUnit i jest odwrotnością metody SetUp. Czyści środowisko testowe po każdym uruchomieniu testu. Możesz to wykorzystać m.in., aby wyczyść dane testowe z bazy danych.
32+
33+### Dekorator testów: OneTimeSetUp i OneTimeTearDown
34+
35+Wymienione powyżej procedury SetUp i TearDown są uruchamiane jednorazowo w każdym teście. Możesz także uruchamiać te procedury raz na jedną instancję/wykonywanie każdego przebiegu testowego.
36+
37+W tym celu użyj OneTimeSetUp i OneTimeTearDown w klasie dziedziczącej po „dekoratorze testów” TTestSetup i zarejestruj ją, np.:
38+
39+``` pascal
40+uses
41+...
42+testdecorator
43+...
44+ TDBBasicsTestSetup = class(TTestSetup)
45+ protected
46+ procedure OneTimeSetUp; override;
47+ procedure OneTimeTearDown; override;
48+ end;
49+...
50+initialization
51+// upewnij się, że zarejestrowałeś swój test wraz z dekoratorem, aby wiedział, jak uruchamiać SetUp/TearDowns
52+ RegisterTestDecorator(TDBBasicsTestSetup, TTestDBBasics);
53+```
54+
55+### Testy
56+
57+Piszesz własne testy jako procedury w sekcji **published** (opublikowane) swojej klasy testowej (w sekcji **private**, **protected** lub **public** nie będą działać). Możesz użyć *AssertEquals* itp., aby określić, co powinno być testowane i dać odpowiedni komunikat, gdy test się nie powiedzie.
58+
59+Jeśli chcesz „oblać test”, możesz m.in. posłużyć się tym:
60+
61+``` pascal
62+if 5=0 then //śmieszny przykład, ale rozumiesz, o co mi chodzi. Możesz użyć innych procedur Assert*, aby znacznie łatwiej przetestować równość itp.
63+ AssertTrue('Ta część kodu nigdy nie powinna zostać wykonana w tym teście.',false);
64+```
65+
66+Jeśli test się nie powiedzie, zostanie zgłoszony wyjątek EAssertionFailedError z komunikatem określonym w Assert*. W ten sposób możesz dodać serię podtestów i stwierdzić, który podtest się nie powiódł. Uwaga: program uruchamiający testy zatrzyma się po pierwszym niepowodzeniu asercji, więc kolejne podtesty nie będą wykonywane. Jeśli chcesz zawsze testować wszystko, podziel te podtesty na osobne procedury testowe.
67+
68+Zamiast procedur Assert* można również użyć procedur Check* kompatybilnych z DUnit (np. CheckEquals), które dają bardziej opisowe komunikaty o błędach w wynikach testu: zawierają wartości oczekiwane i rzeczywiste.
69+
70+Kolejność, w jakiej testy są uruchamiane, to kolejność, w jakiej pojawiają się one w definicji klasy testowej.
71+
72+#### Przykładowy test
73+
74+``` pascal
75+ Ttestexport1 = class(Ttestcase)
76+...
77+ published
78+ procedure TestOutput;
79+...
80+procedure Ttestexport1.TestOutput;
81+const
82+ OutputFilename='output.csv';
83+begin
84+ TestDataSet.Close;
85+
86+ if FileExists(OutputFilename) then DeleteFile(OutputFileName);
87+ TestDataset.FileName:=OutputFileName;
88+ TestDataset.Open;
89+ // Wypełnij dane testowe
90+ TestDataset.Append;
91+ TestDataset.FieldByName('ID').AsInteger := 1;
92+ // Dane z cudzysłowami
93+ TestDataset.FieldByName('NAME').AsString := 'J"T"';
94+ TestDataset.FieldByName('BIRTHDAY').AsDateTime := ScanDateTime('yyyymmdd', '19761231', 1);
95+ TestDataset.Post;
96+
97+ TestDataset.Last;
98+ TestDataset.First;
99+ TestDataset.First;
100+ AssertEquals('Liczba rekordów w testowym dataset', 1, TestDataset.RecordCount);
101+ TestDataset.Close;
102+end;
103+```
104+
105+#### Hierarchia testów
106+
107+W prostych przypadkach Ty (lub Lazarus) rejestrujesz wszystkie swoje testy za pomocą wywołań takich jak:
108+
109+``` pascal
110+uses
111+...
112+testregistry
113+...
114+initialization
115+ RegisterTest(Ttestexport1); //przekazujesz nazwę klasy, aby zarejestrować ją do uruchomienia
116+```
117+
118+Jednak możesz także utworzyć wiele warstw, aby pogrupować testy, gdy Twój projekt stanie się duży:
119+
120+``` pascal
121+initialization
122+ RegisterTest('WorldDominationApp.ExportCheesePlan',Ttestexport1); //Poziomy są oddzielone kropkami
123+ RegisterTest('WorldDominationApp.Obsolete',TtestPinkysBrain1); //inna kategoria
124+```
125+
126+#### Niestandardowe nazwy testów
127+
128+Domyślnie nazwa Twojej klasy potomnej od TTestCase jest używana jako nazwa zestawu testów, a nazwy metod są używane jako nazwy przypadków testowych. Możesz także przypisać własne nazwy, np. jeśli masz klasę, która przeprowadzi różne testy w zależności od innych ustawień.
129+
130+Poniższy kod utworzy test o nazwie MyTestName (zastępując nazwę metody) w MyTestSuiteName (zastępując nazwę klasy).
131+
132+``` pascal
133+interface
134+
135+type
136+ TMyTestClass = class(TTestCase)
137+ protected
138+ // zastąp domyślną obsługę testów, uruchamiając opublikowaną metodę
139+ procedure RunTest; override;
140+ // nie potrzebujesz tutaj żadnej opublikowanej metody
141+ end;
142+
143+implementation
144+
145+procedure TMyTestClass.RunTest;
146+begin
147+ // nie wywołuj metody dziedziczonej.
148+ // tutaj będzie logika twojego testu ...
149+ AssertTrue(False);
150+end;
151+
152+initialization
153+ RegisterTest('MyTestSuiteName', TMyTestClass.CreateWithName('MyTestName');
154+end.
155+```
156+
157+## Automatyczna modyfikacja pól
158+
159+Jeśli dodasz jakiekolwiek pole do podklasy TTestCase, powinieneś mieć świadomość, że te pola zostaną zresetowane do wartości domyślnych przed rozpoczęciem testu. Nie uważam tego za błąd, ponieważ wyniki testów powinny być niezależne: wynik testu nie powinien zależeć od wyniku żadnego innego testu. Odtworzyłem to zachowanie zarówno w systemie Windows, jak i Linux Mint XFCE.
160+
161+Jeśli naprawdę potrzebujesz wiarygodnej wartości zmiennej, użycie *class var* (zmiennej klasy) zamiast pól, rozwiąże problem.
162+
163+Podczas dalszych testów tego modułu odkryłem, że w poniższym kodzie, jeśli zastąpię *fx:double;* przez *class var fx:double;* **test już się nie powiedzie!** Zadeklarowanie jednej zmiennej jako zmiennej klasowej rozwiązało problem. To sprawia, że ​​wierzę, że jest to błąd.
164+
165+Zwykle błędy nie są zapisywane w dokumentacji, ale ten kosztował nas wiele godzin straconego czasu podczas testów jednostkowych. Ponadto przed zgłoszeniem jakiegokolwiek błędu należy jasno określić oczekiwane zachowanie. Ta strona wiki musi opisywać oczekiwane zachowanie. Czy błąd polega na tym, że pola są przypisane do ich domyślnych wartości 0, czy też błąd polega na tym, że po dodaniu klasy var nie są już przypisane do 0? Zgodnie z tym odniesieniem <https://sergworks.wordpress.com/2012/08/31/introduction-to-unit-testing-with-lazarus/>, błąd polegał na tym, że zostały one wyczyszczone do wartości domyślnych.
166+
167+``` pascal
168+unit TestCase1;
169+
170+{$mode objfpc}{$H+}
171+
172+interface
173+
174+uses
175+ Classes, SysUtils, fpcunit, testutils, testregistry, Dialogs;
176+
177+type
178+
179+ TTestCase1= class(TTestCase)
180+ protected
181+ fx:double;
182+ fi:integer;
183+ procedure SetUp; override;
184+ procedure TearDown; override;
185+ published
186+ procedure One;
187+ procedure Two;
188+ end;
189+
190+implementation
191+
192+procedure TTestCase1.One;
193+begin
194+ fx:=0.5;
195+ fi:=3;
196+ IF fi <> 3 THEN
197+ Fail('Musi być 3.');
198+end;
199+procedure TTestCase1.Two;
200+begin
201+ ShowMessage('fx='+fx.ToString);
202+ ShowMessage('fi='+fi.ToString);
203+
204+ IF fi <> 3 THEN //Nie powiedzie się, fi =0, zostało automatycznie wyczyszczone, nawet jeśli test 1 był już przeprowadzany
205+ Fail('Musi być 3.');
206+end;
207+
208+procedure TTestCase1.SetUp;
209+begin
210+
211+end;
212+
213+procedure TTestCase1.TearDown;
214+begin
215+
216+end;
217+
218+initialization
219+
220+ RegisterTest(TTestCase1);
221+end.
222+```
223+
224+## Wyjście
225+
226+Program uruchamiający testy konsoli może wyprowadzać dane wyjściowe w formacie XML (oryginalnym formacie FPCUnit lub bardziej zaawansowanym formacie podobnym do DUnit2, jeśli używasz modułu *xmltestreport*), w formacie zwykłego tekstu i latex (np. nadającego się do eksportu PDF). Program uruchamiający testy GUI w razie potrzeby generuje dane wyjściowe w formacie XML (przy użyciu tego samego formatu XML *xmltestreport*).
227+
228+### Dostosowywanie wyjścia
229+
230+Możesz użyć własnego „obserwatora”, który śledzi wyników testu i wyprowadza dane testowe w dowolny sposób. Utwórz T*Listener, który implementuje interfejs ITestListener. To tylko 5 wymaganych metod do wdrożenia.
231+
232+W aplikacji uruchamiającej testy (np. kopii fpctestconsole), dodaj obiekt obserwatora; zarejestruj tego testowego obserwatora w środowisku testowym (np. w programie uruchamiającym testy konsoli) za pomocą wywołania TestResult.AddListener(), a wyniki testów będą do niego dostarczane w miarę ich pojawiania się.
233+
234+#### Testdbwriter
235+
236+Przykładem niestandardowego obserwatora jest program do zapisywania danych wyjściowych bazy danych dostępny pod adresem <https://bitbucket.org/reiniero/testdbwriter>. Ten program zapisze wszystkie wyniki testów w bazie danych, która jest zoptymalizowana pod kątem otrzymywania dużych ilości wyników testów (przydatne do używania na serwerze CI, takim jak Jenkins lub do importu/konsolidacji wyników testów). Wspomniane repozytorium zawiera przykład, który uruchamia wyniki testów frameworka db do (innej) bazy danych.
237+
238+#### ToDo: dostosuj to; użyj nowego modułu xml
239+
240+Przykładem dostępnego dodatkowego obserwatora jest TXMLResultsWriter w module xmlreporter w \<fpc\>\packages\fcl-fpcunit\src\xmlreporter.pas.
241+
242+*todo: w rzeczywistości dbtestframework wydaje się używać starej metody wyjściowej xml...* Przykład dostosowanego programu uruchamiającego testy, który używa dodatkowego obserwatora, można znaleźć w \<fpc\>\packages\fcl-db\tests\dbtestframework.pas, który zawiera ten kod do wyprowadzenia do niestandardowych obserwatorów (program zapisujący XML i zapisujący skrót, który umieszcza wyjście w archiwum .tar, przydatne do przetwarzania zdalnego):
243+
244+``` pascal
245+uses
246+ //...pozostałe moduły potrzebne do testowania...
247+ fpcunit,...
248+ // moduły z TXMLResultsWriter i TDigestResultsWriter
249+ testreport,DigestTestReport
250+...
251+Procedure LegacyOutput;
252+
253+var
254+ FXMLResultsWriter: TXMLResultsWriter;
255+ FDigestResultsWriter: TDigestResultsWriter;
256+ testResult: TTestResult;
257+
258+begin
259+ testResult := TTestResult.Create;
260+ FXMLResultsWriter := TXMLResultsWriter.Create;
261+ FDigestResultsWriter := TDigestResultsWriter.Create(nil);
262+ try
263+ testResult.AddListener(FXMLResultsWriter);
264+ testResult.AddListener(FDigestResultsWriter);
265+ // Ustaw niektóre właściwości specyficzne dla tego sposobu zapisywania wyników:
266+ FDigestResultsWriter.Comment:=dbtype;
267+ FDigestResultsWriter.Category:='DB';
268+ FDigestResultsWriter.RelSrcDir:='fcl-db';
269+ //WriteHeader jest specyficzny dla tego obserwatora; zapisuje nagłówek do pliku XML
270+ //zauważ, że nie jest wywoływany dla FDigestResultsWriter
271+ FXMLResultsWriter.WriteHeader;
272+ // To wykonuje rzeczywisty przebieg testowy, a dane wyjściowe zostaną przetworzone przez obserwatorów:
273+ GetTestRegistry.Run(testResult);
274+ // Podobnie WriteResult jest specyficzny dla tego obserwatora; zapisuje on
275+ FXMLResultsWriter.WriteResult(testResult);
276+ finally
277+ testResult.Free;
278+ FXMLResultsWriter.Free;
279+ FDigestResultsWriter.Free;
280+ end;
281+end;
282+```
283+
284+## Alternatywy
285+
286+- [DUnit2](http://www.sourceforge.net/projects/dunit2/) — ogromna poprawa w stosunku do oryginalnego DUnit. Pierwotnie napisany tylko dla Delphi i używany przez ogromny zestaw testowy frameworka [[tiOPF]].
287+
288+- [[FPTest/pl|FPTest]] — rozwidlenie DUnit2, które jest dostrojone specjalnie do użytku z kompilatorem Free Pascal.
289+
290+## Lazarus
291+
292+Lazarus posiada moduły uruchamiające testy consoletestrunner i GUI, które można zainstalować, instalując pakiet *FPCUnitTestRunner*. Pomoże to w tworzeniu i uruchamianiu testów jednostkowych za pomocą GUI (lub konsoli, jeśli chcesz).
293+
294+Consoletestrunner jest kompatybilny z FPC, więc nie potrzebujesz Lazarusa, aby go skompilować. Wersja Lazarusa różni się nieco od tej w FPC (np. użycie wyjścia UTF8 itp.).
295+
296+Program GUI jest łatwiejszy w użyciu.
297+
298+W programie GUI, jeśli chcesz uruchomić wszystkie testy, obecnie musisz najpierw kliknąć element testu, zanim zostanie aktywowany przycisk *Run all tests* („Uruchom wszystkie testy”).
299+
300+## GDB błędy/funkcje
301+
302+**Uwaga** (wrzesień 2012): błąd/nieudokumentowana funkcja w debuggerze używanym przez Lazarus/FPC (gdb) oznacza, że ​​przekazanie --all jako parametru uruchomienia nie daje żadnego efektu. Przekazanie tego parametru może być przydatne, gdy debugowanie programów uruchamiających testy fpcunit w konsoli nie przynosi żadnego efektu. Obejście: użyj -a.
303+
304+Zobacz błąd [1](http://bugs.freepascal.org/view.php?id=22893)
305+
306+## Zobacz także
307+
308+- <https://www.freepascal.org/~michael/articles/fpcunit/fpcunit.pdf> Obejmuje użycie zarówno FPC, jak i Lazarusa. Wyjaśnia różne zawiłości klasy. Integracja fragmentów tego pliku PDF z tą dokumentacją (lub odwrotnie) może być bardzo pomocna.
309+- <http://sergworks.wordpress.com/2012/08/31/introduction-to-unit-testing-with-lazarus/> Świetny artykuł o tym, jak uruchomić FPCUnit w zaciszu swojego Lazarus IDE.
310+- <http://www.pp4s.co.uk/main/tu-testing-auto2.html> Przykładowy program, który demonstruje testowanie FPCUnit
311+- ~~<http://www.win.tue.nl/~mousavi/testing/4.pdf>~~ Prezentacja o FPCUnit
312+
313+---
314+*From the Free Pascal wiki, page "fpcunit/pl", as it stood on 2024-05-25 after a change by Slawek, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history