Mockning av statiska metoder och konstruktorer
Utforska avancerade tekniker för att mocka statiska metoder, final-klasser och konstruktorer med Mockito-tillägg som `mockito-inline`.
Mockning av statiska metoder och konstruktorer är en gratis lektion i Testning på avancerad nivå: JUnit, Mockito och integrationstester på CoddyKit. Detta är lektion 2 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Testning på avancerad nivå: JUnit, Mockito och integrationstester, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Testning på avancerad nivå: JUnit, Mockito och integrationstester innehåller totalt 4 lektioner.
Bortom vanliga mockar
Välkommen! Hittills har du lärt dig att mocka gränssnitt och vanliga klasser med Mockito. Men hur är det med de knepiga koddelar som verkar svåra att testa?
Ibland stöter du på statiska metoder, final-klasser eller direkta konstruktoranrop (new MyObject()) i koden du vill testa. Vanliga Mockito kan inte hantera dessa direkt.
När traditionella mockar inte räcker
Varför behöver vi mocka dessa?
- Statiska hjälpfunktioner: Används ofta för vanliga uppgifter, men är svåra att isolera om de har sidoeffekter eller externa beroenden.
- Final-klasser/-metoder: Kan inte ärvas eller åsidosättas, vilket gör traditionell proxybaserad mocking omöjlig.
- Konstruktoranrop (
new): När objekt skapas direkt i en metod blir det svårt att injicera en mock i stället.
Genom att mocka dessa kan du isolera koden som testas, även i komplexa eller äldre system.
Ge Mockito mer kraft
För att övervinna dessa begränsningar erbjuder Mockito avancerade funktioner genom sin inline mock maker, som ofta kallas mockito-inline.
Funktionen använder bytekodmanipulering för att "skriva om" klasser under körning. Därmed kan Mockito mocka sådant som det normalt inte kan, till exempel statiska metoder, final-klasser och till och med konstruktorer.
Det är ett kraftfullt verktyg, men använd det med eftertanke!
Konfigurera projektet
För Mockito-version 3.4.0 och senare är inline mock maker ofta aktiverad som standard eller tillgänglig genom att du använder det vanliga beroendet mockito-core.
Om du använder en äldre version eller stöter på problem kan du behöva deklarera mockito-inline uttryckligen. I de flesta moderna konfigurationer behöver du bara se till att du har en aktuell version av mockito-core.
Så här kan din build.gradle se ut:
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'
}Mocka statiska hjälpfunktioner
För att mocka statiska metoder tillhandahåller Mockito gränssnittet MockedStatic. Du skapar en mockkontext med Mockito.mockStatic() i ett try-with-resources-block. Då är mocken aktiv endast så länge blocket körs.
Vi ska se ett exempel med en verktygsklass:
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());
}
}Kontrollera statiska interaktioner
Precis som med vanliga mockar kan du verifiera interaktioner med statiska metoder. Använd metoden verify() på ditt MockedStatic-objekt.
Det säkerställer att koden som testas anropade den statiska metoden som förväntat, med rätt argument och rätt antal gånger.
Observera Mockito.times(1) i föregående exempel, som används för att kontrollera antalet anrop.
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
}
}Tämja final-klasser
Mock makern mockito-inline gör det också möjligt att mocka final-klasser och final-metoder. Det är särskilt användbart när du arbetar med tredjepartsbibliotek eller äldre kod där klassdesignen inte enkelt kan ändras.
Du mockar final-klasser på samma sätt som vanliga klasser: 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");
}
}Fånga nya objekt
Vad händer om koden skapar nya objekt direkt med new MyObject()? Med MockedConstruction kan du fånga dessa anrop och returnera mockinstanser i stället för riktiga objekt.
Detta är avgörande när du testar klasser som hanterar sina beroenden internt i stället för att ta emot dem via dependency injection.
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
}
}Använd med försiktighet
Även om mocking av statiska metoder och konstruktorer är kraftfullt kan det vara ett tecken på en design som är svår att testa.
- Designlukt: Ett stort beroende av dessa mockar kan tyda på att klasserna är alltför tätt kopplade eller inte följer principerna för dependency injection.
- Läsbarhet: Tester som använder dessa avancerade mockar kan vara svårare att förstå och underhålla.
- När de bör användas: De passar bäst för äldre kod, tredjepartsbibliotek eller situationer där refaktorering inte är genomförbar omedelbart. Prioritera refaktorering för bättre testbarhet när det är möjligt!
Kontroll av avancerad mocking
Vilka av följande påståenden om mockito-inline och avancerade mockingtekniker är SANNA?
Sammanfattning: Avancerad mocking
Bra jobbat! Du har utforskat avancerade Mockito-tekniker:
- Mock makern
mockito-inlinemöjliggör mocking av statiska metoder, final-klasser och konstruktorer. MockedStaticgör det möjligt att stubba och verifiera anrop av statiska metoder inom ett definierat omfång.MockedConstructionhjälper dig att fånga och ersätta objekt som skapas med nyckelordetnew.
Dessa verktyg är kraftfulla när du testar svårtestad kod, men kom ihåg att ta hänsyn till underliggande designmönster. Nästa steg är att lära dig bästa praxis för Mockito!
Lär dig Testning på avancerad nivå: JUnit, Mockito och integrationstester med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 12
- Lektioner
- 48
Vanliga frågor
Är lektionen ”Mockning av statiska metoder och konstruktorer” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Testning på avancerad nivå: JUnit, Mockito och integrationstester, inklusive ”Mockning av statiska metoder och konstruktorer”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Testning på avancerad nivå: JUnit, Mockito och integrationstester innehåller totalt 4 lektioner.
Vad lär jag mig i ”Mockning av statiska metoder och konstruktorer”?
Utforska avancerade tekniker för att mocka statiska metoder, final-klasser och konstruktorer med Mockito-tillägg som `mockito-inline`. Ni övar på Testning på avancerad nivå: JUnit, Mockito och integrationstester med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Testning på avancerad nivå: JUnit, Mockito och integrationstester?
Du behöver inga förkunskaper. Utbildningen i Testning på avancerad nivå: JUnit, Mockito och integrationstester på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.
Hur lång tid tar lektionen ”Mockning av statiska metoder och konstruktorer”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Testning på avancerad nivå: JUnit, Mockito och integrationstester-lektionen?
Ja. Varje Testning på avancerad nivå: JUnit, Mockito och integrationstester-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Anpassade svar och callbacks
- Mockning av statiska metoder och konstruktorer
- Bästa praxis för Mockito
- Fånga argument med ArgumentCaptor