You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
`Testy jednostkowe` (`unit test`) poddają weryfikacji sposób działania różnych elementów składowych kodu takich jak `metody`, `klasy` czy `moduły`. Testy powinny być pisane w sposób `niezależny`, tzn. testowana jednostka nie jest podatna na wpływy innych elementów, w przeciwnym razie wynik testu może być niewiarygodny. Testy jednostkowe należą do `testów automatycznych` za których tworzenie i wykonywanie powinien odpowiadać programista. Warto przeprowadzać je często i regularnie przy każdym nowym przyroście dzięki czemu na wczesnym etapie tworzenia oprogramowania możliwe jest wykrycie usterki. Pozwala to na przeciwdziałanie kumulowania się błędów (jeden błąd rodzi kolejne) co w rezultacie redukuje koszty w póżniejszych etapach cyklu życia aplikacji. Tworzenie testów jednostkowych polega przede wszystkim na pisaniu `asercji` czyli porównywanie uzyskanego wyniku z oczekiwanym. Do przeprowadzania testów jednostkowych można wykorzystać np. bibliotekę `jUnit`. Przeważnie jednostki testowe wymagają do poprawnego działania obiektów różnego typu. Aby przekazywane argumenty nie wpływały na wynik testu danej jednostki (niezależne testy) należy dostarczać tzw. `atrapę` obiektu czyli naiwną implementację zależności.
13
13
14
14
## Testy lokalne i instrumentalne
15
-
Testy (nie tylko jednostkowe), które mogą zostać wykonane na wirtualnej maszynie deweloperskiej nazywane są `testami lokalnymi`. Przeprowadzenie jednostkowych testów lokalnych charakteryzuje się niskim kosztem oraz szybkością w związku z czym powinny stanowić przeważającą część testów. Natomiast testy, które wymagają uruchomienia na fizycznym urządzeniu lub emulatorze nazywane są `testami instrumentalnymi`. Wynika to z faktu, że pewne fragmenty kodu są zależne bibliotek `Android SDK` oraz cyklu życia komponentów, którymi zarządza system. Takie testy w stosunku do testów lokalnych są dosyć kosztowne i powolne. Przykładem biblioteki realizującej instrumentalne testy jednostkowe jest `Robolectrict`.
15
+
Testy (nie tylko jednostkowe), które mogą zostać wykonane na wirtualnej maszynie deweloperskiej nazywane są `testami lokalnymi`. Przeprowadzenie jednostkowych testów lokalnych charakteryzuje się niskim kosztem oraz szybkością w związku z czym powinny stanowić przeważającą część testów. Natomiast testy, które wymagają uruchomienia na fizycznym urządzeniu lub emulatorze nazywane są `testami instrumentalnymi`. Wynika to z faktu, że pewne fragmenty kodu są zależne bibliotek `Android SDK` oraz cyklu życia komponentów, którymi zarządza system. Takie testy w stosunku do testów lokalnych są dosyć kosztowne i powolne. Biblioteka `Robolectrict` umożliwia realizacje lokalnych testów jednostkowych zależnych od Android SDK co może być w wielu przypadkach alternatywą dla kosztownych testów instrumentalnych.
16
16
17
17
## Atrapa i zaślepka
18
18
`Zaślepka` (`stub`) jest minimalną implementacją zależnego modułu używaną podczas testów innego modułu. Ma za zadanie zastępować wywoływany moduł poprzez zwracanie w prosty sposób wyniku bez dokonywania obliczeń w taki sposób, aby wykonywany test zawsze przeszedł pozytywnie. `Atrapa` (`mock`) dostarcza natomiast naiwną implementację zależności, która umożliwia rejestrowanie interakcji z implementowanym interfejsem (np. ilość wywołań i parametry) i w przeciwieństwie do zaślepki bierze udział w procesie testowania. Atrapa jest determinowana w momencie działania programu i reprezentuje instancje oczekiwanego obiektu. Posługując się fachową nomenklaturą można wyróżnić jeszcze szerszy podział obiektów zastępczych jednakże ważniejsze od teoretycznego podziału jest właściwa implementacja. Biblioteka `Mockito` ułatwia tworzenie i zarządzanie naiwnymi implementacjami.
Podstawą procesu testowania jest tworzenie i wykonywanie testów jednostkowych, które odpowiednio napisane w łatwy i wiarygodny sposób weryfikują poprawności logiki jednostki testowanej. Wykonywanie testów jednostkowych przy każdym przyroście ułatwia szybkie wyłapanie błędu. Należy jednak pamiętać o izolacji testowanej jednostki od pozostałych zależności. `JUnit` w Android jest wykorzystywany przede wszystkim do pisania `lokalnych testów` jednostkowych lub prostych `testów instrumentalnych` dla których można dostarczyć zależności (własne lub przy pomocy biblioteki np. Mockito). W pozostałych sytuacjach należy wykorzystać bibliotekę dostarczają zależności środowiska uruchomieniowego np. `Robolectric`. Tworzenie asercji może zostać usprawnione przez wykorzystanie `Hamcrest`. Alternatywą dla implementacji JUnit dla Android jest wykorzystanie biblioteki `Truth` we współpracy z asercjami Android.
23
+
Podstawą procesu testowania jest tworzenie i wykonywanie testów jednostkowych, które odpowiednio napisane w łatwy i wiarygodny sposób weryfikują poprawności logiki jednostki testowanej. Wykonywanie testów jednostkowych przy każdym przyroście ułatwia szybkie wyłapanie błędu. Należy jednak pamiętać o izolacji testowanej jednostki od pozostałych zależności. `JUnit` w Android jest wykorzystywany przede wszystkim do pisania `lokalnych testów` jednostkowych lub prostych `testów instrumentalnych` dla których można dostarczyć zależności (własne lub przy pomocy biblioteki np. Mockito). W pozostałych sytuacjach należy wykorzystać bibliotekę dostarczają zależności środowiska uruchomieniowego np. `Robolectric`. Tworzenie asercji może zostać usprawnione przez wykorzystanie `Hamcrest`. Alternatywą dla implementacji JUnit dla Android jest wykorzystanie biblioteki `Truth` we współpracy z asercjami Android.
24
24
25
25
## Dobre praktyki
26
26
Tworząc metody testowe należy przede wszystkim pamiętać o wykluczeniu wszelkich zależności w taki sposób, aby na wynik testu testowanej jednostki nie miały wpływu inne zależności. Klasy testowe powinny znajdować się w pakiecie o tej samej nazwie co klasy implementacji, a nazwy klas testowych powinny być podobne do klas testowanych. Metody opisowe powinny być nazywane w sposób opisowy i jednoznaczny w nawiązaniu do celu testu nawet jeśli z tego powodu nazwa metody jest długa. W tym celu można posłużyć się konwencją `Given/When/Then`, gdzie `Given` określa warunki początkowe, `When` opisuje akcje, a `Then` informuje o oczekiwanym rezultacie. Ponadto należy dążyć do minimalizacji asercji, czasu wykonywania testów oraz zwiększać pokrycie kodu. Testy powinny być krótkie, proste i ściśle dotyczyć jednej jednostki. Jeśli sytuacja tego wymaga należy wykorzystywać metody cyklu życia testów, aby zapewnić odpowiednią inicjalizację i czyszczenie środowiska.
Copy file name to clipboardExpand all lines: _drafts/2019-01-21-mockito.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -341,4 +341,4 @@ class PowerMockTest {
341
341
}
342
342
{% endhighlight %}
343
343
344
-
Jako alternatywę dla Mockito i PowerMock w `Kotlin` warto rozważyć bibliotekę `Mockk`, która rozwiązuje problemy występujące w Mockito i wspiera natywne cechy Kotlin takie jak np.: rozszerzenia. Framework `Robolectric` umożliwi natomiast przeprowadzanie w łatwy sposób instrumentalnych testów jednostkowych.
344
+
Jako alternatywę dla Mockito i PowerMock w `Kotlin` warto rozważyć bibliotekę `Mockk`, która rozwiązuje problemy występujące w Mockito i wspiera natywne cechy Kotlin takie jak np.: rozszerzenia. Framework `Robolectric` umożliwi natomiast przeprowadzanie w łatwy sposób lokalnych testów jednostkowych zależnych od Android SDK.
Uruchamianie jednostkowych testów instrumentalnych na urządzeniu lub emulatorze jest kosztowne i powolne. Jednakże w wielu sytuacjach nie sposób uciec od testowania logiki kodu powiązanego z komponentami Androida co sprawia, że testy instrumentalne są stosowane pomimo wynikających kosztów. Alternatywnym sposobem testowania kodu zależnego od `Android SDK` może być użycie framework `Robolectric`, który umożliwia przeprowadzanie `lokalnych testów` jednostkowych w środowisku wykonawyczm `JVM` na komponentach Android takich jak m.in. `Activity`, `Fragment`, `Intent`, `Service`, `ContentProvider`. W przeciwieństwie do testów instrumentalnych Robolectric wykonuje się piaskownicy systemowej (`sandbox`) co pozwala na konfiguracje środowiska Android dla wszystkich testów. Robolectric dostarcza również dublerów komponentów Android dla których nie potrafi dokonać tłumaczenia do testów jednostkowych (np. sensory hardware, usługi systemowe). Obsługuje inflację widoków, ładowanie zasobów i wiele innych aspektów zaimplementowanych w natywnym kodzie na urządzeniach co pozwala na wykonanie większości czynności jak na prawidzwym urządzeniu. Robolectric w łatwy sposób umożliwia zapewnienie własnej implementacji wybranych metod Android SDK dzięki czemu możliwa jest np. symulacja warunków czy zachowań sensorów. Wykorzystanie Robolectric jest bliższe podejściu testowania czarnoskrzynkowego (skupionego na zachowaniu) i nie wyklucza jednoczesnego stosowania innych bibliotek naiwnych implementacji takich jak np. `Mockito`.
14
+
15
+
## Uruchomienie
16
+
Aby uruchomić test w Robolectric należy opatrzeć klasę testową adnotacją `@RunWith(RobolectricTestRunner.class)` oraz uzyskać instancję żądanej klasy komponentu.
17
+
18
+
{% highlight kotlin %}
19
+
@RunWith(RobolectricTestRunner::class)
20
+
class SimpleTest {
21
+
22
+
lateinit var activity: MainActivity
23
+
24
+
@Before
25
+
fun init() {
26
+
//this method provides that activity goes throw all create lifecycle
Aby zmienić domyślną konfiguracje testów należy oznaczyć klasy lub metody adnotacją `@Config` wraz z deklaracją konfiguracji. Metody z adnotacją `@Config` nadpisują zachowanie poziomu klasy. Konfiguracji mogą podlegać m.in. poziom `sdk`, plik `manifest`, klasy `shadows`, ścieżki do zasobów czy `kwalifikatory` (np. języka, regionu itp).
59
+
60
+
{% highlight kotlin %}
61
+
@RunWith(RobolectricTestRunner::class)
62
+
@Config(minSdk = LOLLIPOP)
63
+
class ConfigurationTest {
64
+
65
+
lateinit var activity: MainActivity
66
+
67
+
@Before
68
+
fun init() {
69
+
//this method provides that activity goes throw all create lifecycle
`ActivityController` odpowiada za tworzenie oraz zarządzanie cyklem życia tworzonej Aktywności. Metoda `buildActivity` tworzy instancję `ActivityController`, która umożliwia wywołanie wybranych metod cyklu życia oraz pobranie instancji Aktywności. Aby bezpośrednio uzyskać obiekt Aktywności z przebytym pełnym cyklem tworzenia należy wywołać metodę `setupActivity`.
110
+
111
+
{% highlight kotlin %}
112
+
@RunWith(RobolectricTestRunner::class)
113
+
class LifecycleTest {
114
+
115
+
@Test
116
+
fun checkMainActivityHasWorkingFinishLifecycle() {
117
+
//this activity goes throw all create lifecycle
118
+
val controller = Robolectric.buildActivity(MainActivity::class.java)
119
+
val activity = controller.create().start().resume().visible().get()
120
+
//equivalent of val activity = Robolectric.setupActivity(MainActivity::class.java)
121
+
//visible methods assures that activity view's is attached
122
+
123
+
assertFalse(activity.isFinishing)
124
+
activity.finish()
125
+
assertTrue(activity.isFinishing)
126
+
}
127
+
128
+
@Test
129
+
fun checkMainActivityHasWorkingLifecycle() {
130
+
val controller = Robolectric.buildActivity(MainActivity::class.java)
0 commit comments