0Pricing
Android Academy · Lekcja

Testy jednostkowe z JUnit

Pisz szybkie i niezawodne testy jednostkowe za pomocą JUnit 4. Używaj @Test, @Before, @After i asercji, testuj LiveData z InstantTaskExecutorRule oraz korutyny z runTest.

Testy jednostkowe z JUnit to bezpłatna lekcja Android Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Android Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Android Academy zawiera 4 lekcji w sumie.

Po co pisać testy?

Testy nie są luksusem — stanowią siatkę bezpieczeństwa:

  • Wykrywają błędy, zanim zrobią to użytkownicy
  • Pozwalają bez obaw refaktoryzować kod (jeśli testy przechodzą, niczego nie zepsuto)
  • Dokumentują zamierzone działanie
  • Zapobiegają regresjom podczas dodawania funkcji

Dobrze przetestowany kod jest również zwykle lepiej zaprojektowany — jeśli trudno go testować, projekt prawdopodobnie jest zbyt silnie powiązany.

Rodzaje testów Android

Dwie kategorie:

  • Testy jednostkowe (folder test/) — uruchamiane na JVM, bez potrzeby używania urządzenia. Szybkie. Testują zwykłą logikę Kotlin/Java.
  • Testy instrumentacyjne (folder androidTest/) — uruchamiane na urządzeniu lub emulatorze. Wolniejsze. Testują kod zależny od Androida (bazę Room, interfejs użytkownika).

Preferuj testy jednostkowe dla logiki biznesowej. Testów instrumentacyjnych używaj tylko wtedy, gdy musisz korzystać z API Androida.

Konfiguracja JUnit 4

JUnit 4 jest domyślnie dołączony do projektów Android. Dodaj te zależności do app/build.gradle:

// app/build.gradle:
dependencies {
    testImplementation 'junit:junit:4.13.2'
    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3'
    testImplementation 'androidx.arch.core:core-testing:2.2.0'  // for LiveData
}

Pierwszy test JUnit

Utwórz klasę w src/test/java/ i oznaczaj metody testowe adnotacją @Test:

import org.junit.Test
import org.junit.Assert.*

class CalculatorTest {

    private val calc = Calculator()

    @Test
    fun `addition returns correct sum`() {
        val result = calc.add(2, 3)
        assertEquals(5, result)
    }

    @Test
    fun `division by zero throws exception`() {
        assertThrows(ArithmeticException::class.java) {
            calc.divide(10, 0)
        }
    }
}

@Before i @After

Używaj adnotacji cyklu życia, aby przygotowywać i sprzątać stan przed każdym testem i po nim:

class UserRepositoryTest {

    private lateinit var repo: UserRepository
    private lateinit var fakeDao: FakeUserDao

    @Before
    fun setUp() {
        fakeDao = FakeUserDao()          // fresh instance before each test
        repo = UserRepository(fakeDao)
    }

    @After
    fun tearDown() {
        fakeDao.clear()                  // clean up after each test
    }

    @Test
    fun `getUsers returns all users`() {
        fakeDao.insert(User(1, "Alice"))
        fakeDao.insert(User(2, "Bob"))
        assertEquals(2, repo.getUsers().size)
    }
}

Typowe asercje

JUnit udostępnia metody asercji w Assert.*:

// Equality:
assertEquals(expected, actual)
assertNotEquals(unexpected, actual)

// Null:
assertNull(value)
assertNotNull(value)

// Boolean:
assertTrue(condition)
assertFalse(condition)

// Same object reference:
assertSame(expected, actual)

// Custom message on failure:
assertEquals("User ID should be 1", 1, user.id)

// Exception:
assertThrows(IllegalArgumentException::class.java) {
    User(id = -1, name = "")
}

Testowanie ViewModel

Aby testować LiveData, dodaj InstantTaskExecutorRule, dzięki czemu LiveData będzie publikować dane synchronicznie:

class UserViewModelTest {

    @get:Rule
    val instantTaskRule = InstantTaskExecutorRule()

    private val fakeRepo = FakeUserRepository()
    private lateinit var viewModel: UserViewModel

    @Before
    fun setUp() {
        viewModel = UserViewModel(fakeRepo)
    }

    @Test
    fun `users are loaded on init`() {
        fakeRepo.usersToReturn = listOf(User(1, "Alice"), User(2, "Bob"))
        viewModel.loadUsers()

        val result = viewModel.users.value
        assertNotNull(result)
        assertEquals(2, result?.size)
    }
}

Testowanie korutyn

Używaj TestCoroutineDispatcher / StandardTestDispatcher, aby kontrolować wykonywanie korutyn w testach:

class SyncWorkerTest {

    @get:Rule
    val instantTaskRule = InstantTaskExecutorRule()

    private val testDispatcher = StandardTestDispatcher()

    @Before
    fun setUp() {
        Dispatchers.setMain(testDispatcher)
    }

    @After
    fun tearDown() {
        Dispatchers.resetMain()
    }

    @Test
    fun `sync completes successfully`() = runTest {
        val repo = FakeRepository()
        val worker = SyncUseCase(repo, testDispatcher)
        val result = worker.run()
        assertTrue(result.isSuccess)
    }
}

Fake a Mock

Dwie strategie zastępowania rzeczywistych zależności w testach:

  • Fake — działająca implementacja zaprojektowana do testowania (np. lista przechowywana w pamięci zamiast prawdziwej bazy danych). Łatwa do napisania, czytelna i niewymagająca biblioteki.
  • Mock — automatycznie generowany obiekt zastępczy, który rejestruje wywołania i pozwala weryfikować interakcje (Mockito, MockK). Potężniejszy, ale przy nadużywaniu może prowadzić do kruchych testów.

Preferuj obiekty Fake w prostych przypadkach; używaj obiektów Mock, gdy trzeba weryfikować wywołania metod.

Pisanie obiektu Fake

Obiekt Fake implementuje ten sam interfejs co prawdziwa klasa, ale korzysta z przechowywania danych w pamięci:

interface UserDao {
    fun getAll(): List<User>
    fun insert(user: User)
}

class FakeUserDao : UserDao {
    private val storage = mutableListOf<User>()

    override fun getAll(): List<User> = storage.toList()
    override fun insert(user: User) { storage.add(user) }

    fun clear() { storage.clear() }
}

Konwencja nazewnictwa testów

Dobre nazwy testów opisują, co jest testowane, oraz oczekiwany rezultat. W Kotlinie używaj nazw funkcji w backtickach, aby opisy były czytelne:

  • `getUsers returns empty list when no users exist`
  • `login throws exception when password is blank`
  • `add returns correct sum for negative numbers`

Wzorzec: `subject does X when Y`

Szybki test

Jaki jest cel adnotacji @Before w klasie testowej JUnit?

Podsumowanie: testy jednostkowe z JUnit

Niezawodne aplikacje to aplikacje przetestowane:

  • Testy jednostkowe umieszczaj w src/test/; są uruchamiane na JVM — szybko
  • Oznaczaj je adnotacją @Test, używaj assertEquals, assertTrue, assertThrows
  • @Before / @After służą do przygotowania i sprzątania stanu
  • InstantTaskExecutorRule służy do synchronicznego testowania LiveData
  • runTest + StandardTestDispatcher służą do testowania korutyn
  • W przypadku prostych zamienników preferuj obiekty Fake zamiast Mock

Następnie: mockowanie z Mockito w celu weryfikowania interakcji.

Często zadawane pytania

Czy lekcja „Testy jednostkowe z JUnit” jest bezpłatna?

Tak — pełny tekst „Testy jednostkowe z JUnit” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Android Academy, przejdź na CoddyKit PRO. Kurs Android Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Testy jednostkowe z JUnit”?

Pisz szybkie i niezawodne testy jednostkowe za pomocą JUnit 4. Używaj @Test, @Before, @After i asercji, testuj LiveData z InstantTaskExecutorRule oraz korutyny z runTest. Ćwiczysz Android Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Android Academy?

Nie wymagamy żadnego doświadczenia. Android Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Testy jednostkowe z JUnit”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Android Academy?

Tak. Każda lekcja Android Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Testy jednostkowe z JUnit
  2. Mockowanie za pomocą Mockito
  3. Testowanie interfejsu z Espresso
  4. Debugowanie i profilowanie
← Powrót do Android Academy