Testauksen hallinta: JUnit, Mockito ja integraatiotestit · Oppitunti

Staattisten metodien ja konstruktorien mockaus

Tutustukaa edistyneisiin tekniikoihin, joilla staattisia metodeja, final-luokkia ja konstruktoreja voidaan mockata Mockito-laajennuksilla, kuten `mockito-inline`.

Oppitunti 2/411 vaihetta

Staattisten metodien ja konstruktorien mockaus on ilmainen Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Testauksen hallinta: JUnit, Mockito ja integraatiotestit-kurssilla on yhteensä 4 oppituntia.

Tavallisia mock-objekteja pidemmälle

Tervetuloa! Tähän mennessä olet oppinut mockaamaan rajapintoja ja tavallisia luokkia Mockiton avulla. Entä sitten ne hankalat koodin osat, jotka vaikuttavat vastustavan testaamista?

Joskus testattavassa koodissa tulee vastaan staattisia metodeja, final-luokkia tai suoria konstruktorikutsuja (new MyObject()). Tavallinen Mockito ei pysty käsittelemään näitä suoraan.

Kun perinteiset mockit eivät riitä

Miksi näitä pitää mockata?

  • Staattiset apumetodit: Niitä käytetään usein yleisiin tehtäviin, mutta niitä on vaikea eristää, jos niillä on sivuvaikutuksia tai ulkoisia riippuvuuksia.
  • Final-luokat ja -metodit: Niitä ei voi periä tai ylikirjoittaa, joten perinteinen välityspalvelimeen perustuva mockaaminen ei ole mahdollista.
  • Konstruktorikutsut (new): Suora olion luominen metodin sisällä vaikeuttaa mockin injektoimista sen tilalle.

Näiden mockaaminen auttaa eristämään testattavan koodin myös monimutkaisissa tai vanhoissa järjestelmissä.

Mockiton tehostaminen

Rajoitusten kiertämiseksi Mockito tarjoaa edistyneitä ominaisuuksia inline mock maker-toiminnolla, josta käytetään usein nimitystä mockito-inline.

Toiminto käyttää tavukoodin muokkausta luokkien "uudelleenkirjoittamiseen" ajon aikana. Näin Mockito voi mockata asioita, joita se ei normaalisti pysty käsittelemään, kuten staattisia metodeja, final-luokkia ja jopa konstruktoreita.

Kyseessä on tehokas työkalu, mutta käytä sitä harkiten!

Projektin määrittäminen

Mockito-versioissa 3.4.0 ja uudemmissa inline mock maker on usein käytössä oletusarvoisesti tai saatavilla yksinkertaisesti käyttämällä tavallista mockito-core-riippuvuutta.

Jos käytät vanhempaa versiota tai kohtaat ongelmia, sinun on ehkä määritettävä mockito-inline erikseen. Useimmissa nykyaikaisissa asetuksissa riittää, että käytössäsi on ajantasainen mockito-core-versio.

build.gradle-tiedostosi voi näyttää tältä:

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.0'
    testImplementation 'org.mockito:mockito-core:5.8.0' // Includes inline mock maker
    // For older Mockito versions, you might need:
    // testImplementation 'org.mockito:mockito-inline:5.8.0'
}

Staattisten apumetodien mockaaminen

Staattisten metodien mockaamista varten Mockito tarjoaa MockedStatic-rajapinnan. Luot mock-kontekstin käyttämällä Mockito.mockStatic()-metodia try-with-resources-lohkon sisällä. Näin mock on aktiivinen vain kyseisen lohkon ajan.

Katsotaan esimerkkiä apuluokan kanssa:

import org.mockito.Mockito;
import org.mockito.MockedStatic;

// Utility class with a static method
class MyStaticService {
    public static String getGreeting() {
        return "Hello from real static service!";
    }
    public static int add(int a, int b) {
        return a + b;
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("Before mock: " + MyStaticService.getGreeting());

        // Mock the static method within a try-with-resources
        try (MockedStatic<MyStaticService> mockedStatic = Mockito.mockStatic(MyStaticService.class)) {
            mockedStatic.when(MyStaticService::getGreeting).thenReturn("Hello from mocked static!");
            mockedStatic.when(() -> MyStaticService.add(1, 2)).thenReturn(100);

            System.out.println("During mock (greeting): " + MyStaticService.getGreeting());
            System.out.println("During mock (add): " + MyStaticService.add(1, 2));
            System.out.println("During mock (add other): " + MyStaticService.add(5, 5)); // Not mocked, returns 0 by default

            // Verify calls (typically in a test assertion)
            mockedStatic.verify(MyStaticService::getGreeting);
            mockedStatic.verify(() -> MyStaticService.add(1, 2), Mockito.times(1));

        } // Mock is closed here

        System.out.println("After mock: " + MyStaticService.getGreeting());
    }
}

Staattisten vuorovaikutusten tarkistaminen

Aivan kuten tavallisten mockien kanssa, voit tarkistaa myös staattisten metodien vuorovaikutukset. Käytä verify()-metodia MockedStatic-oliosi kanssa.

Näin varmistat, että testattava koodisi kutsui staattista metodia odotetulla tavalla oikeilla argumenteilla ja oikean määrän kertoja.

Huomaa edellisessä esimerkissä oleva Mockito.times(1), jolla tarkistetaan kutsujen määrä.

import org.mockito.Mockito;
import org.mockito.MockedStatic;

// Class from previous scene
class MyStaticService {
    public static String getGreeting() { return "Hello from real static!"; }
    public static int multiply(int a, int b) { return a * b; }
}

public class Main {
    public static void main(String[] args) {
        // Simulate a scenario where a static method is called
        System.out.println("Initial call: " + MyStaticService.multiply(2, 3));

        try (MockedStatic<MyStaticService> mockedStatic = Mockito.mockStatic(MyStaticService.class)) {
            mockedStatic.when(() -> MyStaticService.multiply(2, 3)).thenReturn(777);
            mockedStatic.when(() -> MyStaticService.multiply(5, 5)).thenReturn(123);

            // Call the static method through the mock
            System.out.println("Mocked call 1: " + MyStaticService.multiply(2, 3));
            System.out.println("Mocked call 2: " + MyStaticService.multiply(5, 5));

            // Verify specific calls
            mockedStatic.verify(() -> MyStaticService.multiply(2, 3), Mockito.times(1));
            mockedStatic.verify(() -> MyStaticService.multiply(5, 5), Mockito.atLeastOnce());
            // Verify that a different call was NOT made
            mockedStatic.verify(() -> MyStaticService.multiply(10, 10), Mockito.never());

            System.out.println("Verifications completed.");

        } // Mock is closed here
    }
}

Final-luokkien hallinta

mockito-inline-mock maker mahdollistaa myös final-luokkien ja final-metodien mockaamisen. Tämä on erityisen hyödyllistä kolmansien osapuolten kirjastojen tai vanhan koodin kanssa, kun luokkien rakennetta ei voi helposti muuttaa.

Final-luokat mockataan samalla tavalla kuin tavalliset luokat: Mockito.mock(FinalClass.class).

import org.mockito.Mockito;

// A final class that cannot be extended normally
final class FinalProcessor {
    public final String process(String input) {
        return "Real processed: " + input.toUpperCase();
    }
    public int getVersion() {
        return 1;
    }
}

public class Main {
    public static void main(String[] args) {
        FinalProcessor realProcessor = new FinalProcessor();
        System.out.println("Real output: " + realProcessor.process("data"));
        System.out.println("Real version: " + realProcessor.getVersion());

        // Mocking a final class
        FinalProcessor mockProcessor = Mockito.mock(FinalProcessor.class);

        // Stubbing a final method
        Mockito.when(mockProcessor.process("data")).thenReturn("Mocked processed: data");
        Mockito.when(mockProcessor.getVersion()).thenReturn(99);

        System.out.println("Mocked output: " + mockProcessor.process("data"));
        System.out.println("Mocked version: " + mockProcessor.getVersion());

        // Verify interaction with the mocked final class
        Mockito.verify(mockProcessor).process("data");
    }
}

Uusien olioiden kutsujen sieppaaminen

Mitä jos koodisi luo olioita suoraan käyttämällä new MyObject()-kutsua? MockedConstruction mahdollistaa näiden kutsujen sieppaamisen ja mock-instanssien palauttamisen oikeiden olioiden sijaan.

Tämä on olennaista testattaessa luokkia, jotka hallitsevat riippuvuuksiaan sisäisesti sen sijaan, että vastaanottaisivat ne riippuvuuksien injektoinnin kautta.

import org.mockito.Mockito;
import org.mockito.MockedConstruction;

// A class that creates another object internally
class DependentService {
    private final Helper helper;

    public DependentService() {
        this.helper = new Helper(); // Direct constructor call
    }

    public String doWork() {
        return "Service working with: " + helper.getGreeting();
    }
}

// The class whose constructor we want to mock
class Helper {
    public String getGreeting() {
        return "Real Helper greeting";
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("Without mock:");
        DependentService realService = new DependentService();
        System.out.println(realService.doWork());

        System.out.println("\nWith mocked construction:");
        // Mock the constructor of Helper
        try (MockedConstruction<Helper> mockedConstruction = Mockito.mockConstruction(Helper.class,
                (mock, context) -> {
                    // This block runs every time new Helper() is called
                    Mockito.when(mock.getGreeting()).thenReturn("Mocked Helper greeting!");
                    System.out.println("Helper constructor intercepted!");
                })) {

            // When DependentService() is called, it calls new Helper(),
            // which now returns our stubbed mock.
            DependentService serviceWithMockedHelper = new DependentService();
            System.out.println(serviceWithMockedHelper.doWork());

            // You can get all constructed mocks
            Helper constructedMock = mockedConstruction.constructed().get(0);
            Mockito.verify(constructedMock).getGreeting(); // Verify interaction with the mock
            System.out.println("Verified mock interaction.");

        } // MockedConstruction is closed here
    }
}

Käytä harkiten

Vaikka staattisten metodien ja konstruktoreiden mockaaminen on tehokasta, se voi olla merkki vaikeasti testattavasta suunnittelusta.

  • Suunnitteluongelma: Runsas näiden mockien käyttö voi viitata siihen, että luokkasi ovat liian tiukasti kytkettyjä tai eivät noudata riippuvuuksien injektoinnin periaatteita.
  • Luettavuus: Näitä edistyneitä mockeja käyttävät testit voivat olla vaikeampia ymmärtää ja ylläpitää.
  • Milloin niitä kannattaa käyttää: Ne sopivat parhaiten vanhaan koodiin, kolmansien osapuolten kirjastoihin tai tilanteisiin, joissa uudelleenjärjestely ei ole heti mahdollista. Aseta testattavuuden parantaminen etusijalle aina, kun se on mahdollista!

Edistyneen mockaamisen testi

Mitkä seuraavista mockito-inline-toimintoa ja edistyneitä mockaustekniikoita koskevista väitteistä ovat TOSIA?

Edistyneen mockaamisen kertaus

Hienoa työtä! Olet tutustunut Mockiton edistyneisiin tekniikoihin:

  • mockito-inline-mock maker mahdollistaa staattisten metodien, final-luokkien ja konstruktoreiden mockaamisen.
  • MockedStatic mahdollistaa staattisten metodikutsujen stubbaamisen ja tarkistamisen määritetyssä laajuudessa.
  • MockedConstruction auttaa sieppaamaan ja korvaamaan new-avainsanalla luodut oliot.

Nämä työkalut ovat tehokkaita haastavan koodin testaamisessa, mutta muista huomioida taustalla olevat suunnittelumallit. Seuraavaksi opit Mockiton parhaista käytännöistä!

Aloita maksutta

Opi Testauksen hallinta: JUnit, Mockito ja integraatiotestit tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
12
Oppitunnit
48

Usein kysytyt kysymykset

Onko oppitunti ”Staattisten metodien ja konstruktorien mockaus” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppimispolun 3 oppituntia, myös oppitunnin “Staattisten metodien ja konstruktorien mockaus”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Testauksen hallinta: JUnit, Mockito ja integraatiotestit-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Staattisten metodien ja konstruktorien mockaus”?

Tutustukaa edistyneisiin tekniikoihin, joilla staattisia metodeja, final-luokkia ja konstruktoreja voidaan mockata Mockito-laajennuksilla, kuten `mockito-inline`. Harjoittelet Testauksen hallinta: JUnit, Mockito ja integraatiotestit-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Testauksen hallinta: JUnit, Mockito ja integraatiotestit-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.

Kuinka kauan ”Staattisten metodien ja konstruktorien mockaus”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppitunnilla?

Kyllä. Jokainen Testauksen hallinta: JUnit, Mockito ja integraatiotestit-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Mukautetut vastaukset ja callback-funktiot
  2. Staattisten metodien ja konstruktorien mockaus
  3. Mockiton parhaat käytännöt
  4. Argumenttien kaappaaminen ArgumentCaptorilla
← Takaisin: Testauksen hallinta: JUnit, Mockito ja integraatiotestit