Für alle Java-Devs, die nicht im Testing-Fachjargon ertrinken wollen! ☕


Seiteninhalt

🎯 Java Testing Basics – Das Fundament

JUnit Test

Was es ist: Der Standard für Tests in Java
Einfach gesagt: Java-Klasse mit @Test Annotationen
Beispiel:

import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

class CalculatorTest {
    @Test
    void shouldAddTwoNumbers() {
        Calculator calc = new Calculator();
        int result = calc.add(2, 3);
        assertThat(result).isEqualTo(5);
    }
}

@Test Annotation

Was es ist: Markiert eine Java-Methode als Test
Einfach gesagt: „Diese Methode ist ein Test, führe sie aus!“
JUnit 5: @org.junit.jupiter.api.Test JUnit 4: @org.junit.Test

Test Class (Test-Klasse)

Was es ist: Java-Klasse die Tests für eine andere Klasse enthält
Naming Convention: {KlassenName}Test.java
Beispiel: Calculator.java → CalculatorTest.java


📊 Java Coverage-Tools

JaCoCo (Java Code Coverage)

Was es ist: Standard Coverage-Tool für Java
Einfach gesagt: Zeigt dir welche Java-Zeilen von Tests ausgeführt werden
Maven Plugin:

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.8</version>
</plugin>

Report ansehen: target/site/jacoco/index.html nach mvn test

Line Coverage in Java

Was es ist: Prozentsatz der Java-Code-Zeilen die von Tests durchlaufen werden Beispiel:

public class PaymentService {
    public String processPayment(BigDecimal amount) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) {    // Zeile 1 ✅
            return "Invalid amount";                      // Zeile 2 ❌ nicht getestet
        }
        return "Payment processed";                       // Zeile 3 ✅
    }
}

// Line Coverage = 66% (2 von 3 Zeilen getestet)

Branch Coverage in Java

Was es ist: Prozentsatz der if/else/switch-Pfade die getestet werden Beispiel:

public String checkAge(int age) {
    if (age >= 18) {
        return "adult";     // Branch A ✅ getestet
    } else {
        return "minor";     // Branch B ❌ nicht getestet
    }
}

// Branch Coverage = 50% (nur if-Pfad getestet, else-Pfad vergessen)

🧪 Java Test-Frameworks & Tools

JUnit 5 (Jupiter)

Was es ist: Aktuelles Standard-Test-Framework für Java
Vorteile: Moderne Annotations, bessere Assertions, Parameter-Tests Dependency:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

AssertJ (für Java)

Was es ist: Fluent Assertion-Library für Java
Einfach gesagt: Macht Java-Test-Assertions lesbar
Dependency:

<dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
    <version>3.24.2</version>
    <scope>test</scope>
</dependency>

Java-Beispiele:

// Standard JUnit (schlecht lesbar):
assertEquals(5, list.size());
assertTrue(user.isActive());

// AssertJ (gut lesbar):
assertThat(list).hasSize(5);
assertThat(user.isActive()).isTrue();
assertThat(order.getItems())
    .hasSize(3)
    .extracting(Item::getName)
    .containsExactly("Book", "Pen", "Notebook");

Mockito (für Java)

Was es ist: Standard-Mocking-Framework für Java
Einfach gesagt: Erstellt Fake-Java-Objekte für Tests
Dependency:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.1.1</version>
    <scope>test</scope>
</dependency>

Java-Beispiel:

@ExtendWith(MockitoExtension.class)
class OrderServiceTest {
    @Mock
    private PaymentService paymentService;  // Fake PaymentService
    
    @InjectMocks
    private OrderService orderService;      // Echte OrderService mit injiziertem Mock
    
    @Test
    void shouldCreateOrder() {
        // Mock konfigurieren
        when(paymentService.processPayment(any(PaymentRequest.class)))
            .thenReturn(PaymentResult.success("PAY-123"));
        
        // Test ausführen
        Order order = orderService.createOrder(orderRequest);
        
        // Verifizieren
        assertThat(order.getStatus()).isEqualTo(OrderStatus.CONFIRMED);
        verify(paymentService).processPayment(any(PaymentRequest.class));
    }
}

🏗️ Spring Boot Testing

@SpringBootTest

Was es ist: Startet kompletten Spring-Kontext für Tests
Einfach gesagt: „Lade die ganze Spring-Anwendung für diesen Test“
Langsam aber realistisch:

@SpringBootTest
class OrderServiceIntegrationTest {
    @Autowired
    private OrderService orderService;  // Echte Spring Bean
    
    @Test
    void shouldCreateOrderWithRealSpringContext() {
        Order order = orderService.createOrder(orderRequest);
        assertThat(order).isNotNull();
    }
}

@WebMvcTest

Was es ist: Testet nur die Web-Layer (Controller) ohne kompletten Spring-Kontext
Einfach gesagt: „Teste nur meinen REST Controller, nicht die ganze App“

@WebMvcTest(OrderController.class)
class OrderControllerTest {
    @Autowired
    private MockMvc mockMvc;  // Simuliert HTTP-Requests
    
    @MockBean
    private OrderService orderService;  // Spring Boot Mock
    
    @Test
    void shouldCreateOrderViaHttp() throws Exception {
        when(orderService.createOrder(any())).thenReturn(testOrder);
        
        mockMvc.perform(post("/api/orders")
                .contentType(MediaType.APPLICATION_JSON)
                .content(orderJson))
                .andExpect(status().isCreated())
                .andExpect(jsonPath("$.id").value(123));
    }
}

@DataJpaTest

Was es ist: Testet nur die JPA-Repository-Layer
Einfach gesagt: „Teste nur meine Datenbank-Zugriffe“

@DataJpaTest
class OrderRepositoryTest {
    @Autowired
    private TestEntityManager entityManager;  // Test-DB-Manager
    
    @Autowired  
    private OrderRepository orderRepository;
    
    @Test
    void shouldFindOrdersByStatus() {
        // Given
        Order order = new Order("Test Order", OrderStatus.PENDING);
        entityManager.persistAndFlush(order);
        
        // When
        List<Order> pendingOrders = orderRepository.findByStatus(OrderStatus.PENDING);
        
        // Then
        assertThat(pendingOrders).hasSize(1);
        assertThat(pendingOrders.get(0).getTitle()).isEqualTo("Test Order");
    }
}

🐳 Testcontainers (für Java)

Testcontainers

Was es ist: Docker-Container in Java-Tests verwenden
Einfach gesagt: „Starte echte PostgreSQL/Redis/etc. für Tests“
Dependency:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>1.17.6</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>postgresql</artifactId>
    <version>1.17.6</version>
    <scope>test</scope>
</dependency>

Java-Beispiel:

@Testcontainers
class OrderRepositoryIntegrationTest {
    
    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15")
            .withDatabaseName("testdb")
            .withUsername("test")
            .withPassword("test");
    
    @DynamicPropertySource
    static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }
    
    @Test
    void shouldPersistOrderInRealPostgreSQL() {
        // Test mit echter PostgreSQL-Datenbank!
    }
}

🔬 Java-spezifische Advanced Testing

PIT Mutation Testing (für Java)

Was es ist: Java-Tool das Code-Mutationen erstellt und testet
Einfach gesagt: „Ändere Java-Code automatisch und prüfe ob Tests versagen“
Maven Plugin:

<plugin>
    <groupId>org.pitest</groupId>
    <artifactId>pitest-maven</artifactId>
    <version>1.15.2</version>
    <dependencies>
        <dependency>
            <groupId>org.pitest</groupId>
            <artifactId>pitest-junit5-plugin</artifactId>
            <version>1.2.1</version>
        </dependency>
    </dependencies>
</plugin>

Ausführung: mvn org.pitest:pitest-maven:mutationCoverage
Report: target/pit-reports/index.html

jqwik (Property-Based Testing für Java)

Was es ist: Java-Framework für automatisch generierte Test-Daten
Einfach gesagt: „Generiere 1000 zufällige Java-Objekte zum Testen“
Dependency:

<dependency>
    <groupId>net.jqwik</groupId>
    <artifactId>jqwik</artifactId>
    <version>1.7.4</version>
    <scope>test</scope>
</dependency>

Java-Beispiel:

class StringValidationTest {
    @Property
    void validStringsShouldNeverBeEmpty(@ForAll @StringLength(min = 1, max = 100) String input) {
        ValidationResult result = validator.validate(input);
        
        if (result.isValid()) {
            assertThat(input).isNotEmpty();
            assertThat(input.trim()).isNotEmpty();
        }
    }
}

Pact (Contract Testing für Java)

Was es ist: Java-Tool für API-Contract-Testing zwischen Services
Einfach gesagt: „Stelle sicher dass API-Changes andere Java-Services nicht brechen“ Dependency:

<dependency>
    <groupId>au.com.dius.pact.consumer</groupId>
    <artifactId>junit5</artifactId>
    <version>4.4.1</version>
    <scope>test</scope>
</dependency>

📦 Java Build-Tool Integration

Maven Surefire Plugin

Was es ist: Standard Maven-Plugin das JUnit-Tests ausführt
Einfach gesagt: mvn test führt deine Java-Tests aus
Config:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M9</version>
    <configuration>
        <includes>
            <include>**/*Test.java</include>
            <include>**/*Tests.java</include>
        </includes>
    </configuration>
</plugin>

Gradle Test Task

Was es ist: Gradle-Task der JUnit-Tests ausführt
Einfach gesagt: gradle test für Gradle-Projekte
Config:

test {
    useJUnitPlatform()  // Für JUnit 5
    testLogging {
        events "passed", "skipped", "failed"
    }
}

🎯 Java Test-Naming-Conventions

Test-Klassen-Naming:

  • Calculator.javaCalculatorTest.java
  • OrderService.javaOrderServiceTest.java
  • UserController.javaUserControllerTest.java

Test-Methoden-Naming:

class OrderServiceTest {
    @Test
    void shouldCreateOrderWhenValidRequest() { }
    
    @Test  
    void shouldThrowExceptionWhenInvalidPayment() { }
    
    @Test
    void shouldReturnEmptyListWhenNoOrdersExist() { }
}

Pattern: should{ExpectedBehavior}When{Condition}


🏗️ Java Test-Struktur-Patterns

AAA in Java:

@Test
void shouldCalculateDiscountForPremiumCustomers() {
    // Arrange (Given)
    Customer premiumCustomer = new Customer("John", CustomerType.PREMIUM);
    Order order = new Order(new BigDecimal("1000"));
    DiscountService discountService = new DiscountService();
    
    // Act (When)  
    BigDecimal discount = discountService.calculateDiscount(premiumCustomer, order);
    
    // Assert (Then)
    assertThat(discount).isEqualByComparingTo(new BigDecimal("100")); // 10% discount
}

Test Data Builder Pattern (Java):

public class OrderTestDataBuilder {
    private String customerId = "CUST-DEFAULT";
    private BigDecimal amount = new BigDecimal("100.00");
    private OrderStatus status = OrderStatus.PENDING;
    
    public OrderTestDataBuilder withCustomer(String customerId) {
        this.customerId = customerId;
        return this;
    }
    
    public OrderTestDataBuilder withAmount(BigDecimal amount) {
        this.amount = amount;  
        return this;
    }
    
    public Order build() {
        return new Order(customerId, amount, status);
    }
    
    public static OrderTestDataBuilder anOrder() {
        return new OrderTestDataBuilder();
    }
}

// Verwendung in Tests:
@Test
void shouldApplyVipDiscount() {
    Order vipOrder = anOrder()
        .withCustomer("VIP-CUSTOMER")
        .withAmount(new BigDecimal("5000.00"))
        .build();
        
    // Test logic...
}

🚨 Java-spezifische Testing-Fallstricke

BigDecimal Testing

❌ Falsch:

assertThat(price).isEqualTo(new BigDecimal("19.99"));  // Kann fehlschlagen wegen Scale!

✅ Richtig:

assertThat(price).isEqualByComparingTo(new BigDecimal("19.99"));  // Scale-unabhängig

Date/Time Testing

❌ Falsch:

assertThat(order.getCreatedAt()).isEqualTo(LocalDateTime.now());  // Timing-Problem!

✅ Richtig:

assertThat(order.getCreatedAt()).isCloseTo(LocalDateTime.now(), within(1, ChronoUnit.SECONDS));

Exception Testing

❌ Falsch:

@Test(expected = IllegalArgumentException.class)  // JUnit 4 Style
void shouldThrowException() {
    service.processInvalidData("invalid");
}

✅ Richtig (JUnit 5):

@Test
void shouldThrowExceptionForInvalidData() {
    assertThatThrownBy(() -> service.processInvalidData("invalid"))
        .isInstanceOf(IllegalArgumentException.class)
        .hasMessage("Data cannot be invalid");
}

📊 Java Testing Cheat-Sheet

Tool/FrameworkZweckMaven Dependency
JUnit 5Test-Frameworkjunit-jupiter
AssertJFluent Assertionsassertj-core
MockitoMockingmockito-core
JaCoCoCoveragejacoco-maven-plugin
TestcontainersDocker in Teststestcontainers
jqwikProperty Testingjqwik
PITMutation Testingpitest-maven
PactContract Testingpact-jvm-junit5

Wichtige Maven Commands:

mvn test                    # Tests ausführen
mvn test -Dtest=Calculator  # Nur CalculatorTest ausführen  
mvn jacoco:report          # Coverage Report
mvn org.pitest:pitest-maven:mutationCoverage  # Mutation Testing

Wichtige Gradle Commands:

gradle test                # Tests ausführen
gradle test --tests *Calculator*  # Nur Calculator-Tests
gradle jacocoTestReport    # Coverage Report

🎯 Java Testing Best Practices

Package-Struktur:

src/
├── main/java/com/company/
│   ├── service/OrderService.java
│   └── model/Order.java
└── test/java/com/company/
    ├── service/OrderServiceTest.java
    └── model/OrderTest.java

Test Resource Files:

src/test/resources/
├── application-test.properties
├── test-data.json  
└── schema.sql

Spring Profile für Tests:

# src/test/resources/application-test.properties
spring.profiles.active=test
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.hibernate.ddl-auto=create-drop
logging.level.org.springframework.web=DEBUG

Jetzt sollten alle Java Testing-Posts perfekt verständlich sein! ☕🎯

Das Glossar ist speziell für Java-Entwickler – mit echten Tools, Dependencies und Code-Beispielen!


Tags: #Java #Testing #JUnit #SpringBoot #Maven #AssertJ #Mockito #TestingBasics #JavaDeveloper


🎯 Basis-Begriffe – Das Fundament

Test

Was es ist: Ein Stück Code, das prüft ob anderer Code funktioniert
Einfach gesagt: „Wenn ich diese Funktion mit Input X aufrufe, erwarte ich Output Y“
Beispiel:

@Test
void shouldAddTwoNumbers() {
    Calculator calc = new Calculator();
    int result = calc.add(2, 3);
    assertThat(result).isEqualTo(5); // Erwartung: 2+3 = 5
}

Test Case (Test-Fall)

Was es ist: Ein einzelner Test für ein spezifisches Szenario
Einfach gesagt: Eine konkrete Situation die du testen willst
Beispiel: „Was passiert wenn ich zwei positive Zahlen addiere?“

Test Suite (Test-Sammlung)

Was es ist: Eine Gruppe von Tests die zusammen gehören
Einfach gesagt: Alle Tests für eine Klasse oder ein Feature zusammengefasst
Beispiel: Alle Tests für die Calculator-Klasse = Calculator-Test-Suite


📊 Coverage-Begriffe – „Wie viel wird getestet?“

Test Coverage (Test-Abdeckung)

Was es ist: Prozentsatz des Codes der von Tests ausgeführt wird
Einfach gesagt: „Welcher Anteil meines Codes wird überhaupt von Tests berührt?“
Beispiel: 80% Coverage = 80% deiner Code-Zeilen werden von Tests durchlaufen

Visualisierung:

public class Calculator {
    public int add(int a, int b) {
        return a + b;           // ✅ Diese Zeile wird von Tests ausgeführt
    }
    
    public int subtract(int a, int b) {
        return a - b;           // ❌ Diese Zeile wird NIE von Tests ausgeführt
    }
}

// Test Coverage = 50% (1 von 2 Methoden getestet)

Line Coverage (Zeilen-Abdeckung)

Was es ist: Prozentsatz der Code-Zeilen die von Tests ausgeführt werden
Einfach gesagt: „Wie viele Zeilen meines Codes werden getestet?“
Wichtig: Hohe Line Coverage ≠ gute Tests!

Branch Coverage (Zweig-Abdeckung)

Was es ist: Prozentsatz der if/else-Pfade die getestet werden
Einfach gesagt: „Teste ich alle möglichen Wege durch meinen Code?“

Beispiel:

public String checkAge(int age) {
    if (age >= 18) {
        return "adult";     // Pfad A
    } else {
        return "minor";     // Pfad B  
    }
}

// 100% Branch Coverage = beide Pfade (A und B) werden getestet
// 50% Branch Coverage = nur einer der Pfade wird getestet

🔬 Test-Arten – „Was wird wie getestet?“

Unit Test (Einheiten-Test)

Was es ist: Testet eine einzelne Klasse/Methode isoliert
Einfach gesagt: „Funktioniert diese eine Sache für sich alleine?“
Charakteristikum: Schnell, keine Datenbank, keine Netzwerk-Calls

@Test
void shouldCalculateInterest() {
    LoanCalculator calc = new LoanCalculator();
    BigDecimal interest = calc.calculateInterest(1000, 5.0);
    assertThat(interest).isEqualTo(new BigDecimal("50.00"));
}

Integration Test (Integrations-Test)

Was es ist: Testet ob mehrere Komponenten zusammen funktionieren
Einfach gesagt: „Funktionieren diese Teile zusammen?“
Beispiel: Service + Datenbank + Controller zusammen testen

End-to-End Test (E2E-Test)

Was es ist: Testet die komplette Anwendung wie ein echter User
Einfach gesagt: „Funktioniert das ganze System aus User-Sicht?“
Beispiel: Browser-Test der eine komplette User-Journey simuliert


🏗️ Test-Struktur-Begriffe

AAA Pattern (Arrange-Act-Assert)

Was es ist: Standard-Struktur für Tests
Einfach gesagt:

  • Arrange: Test-Daten vorbereiten
  • Act: Die zu testende Aktion ausführen
  • Assert: Prüfen ob das Ergebnis stimmt
@Test
void shouldTransferMoney() {
    // Arrange - Vorbereitung
    Account fromAccount = new Account(1000);
    Account toAccount = new Account(500);
    
    // Act - Aktion
    transferService.transfer(fromAccount, toAccount, 200);
    
    // Assert - Prüfung
    assertThat(fromAccount.getBalance()).isEqualTo(800);
    assertThat(toAccount.getBalance()).isEqualTo(700);
}

Test Data (Test-Daten)

Was es ist: Daten die für Tests verwendet werden
Einfach gesagt: Input-Werte und erwartete Output-Werte für Tests
Beispiel: Test-User, Test-Orders, Test-Payments

Mock (Schein-Objekt)

Was es ist: Fake-Version einer echten Komponente für Tests
Einfach gesagt: „Tu so als wärst du die Datenbank/API/Service“
Warum: Tests sollen schnell sein und nicht von externen Systemen abhängen

@Mock
private PaymentService paymentService;  // Fake PaymentService

@Test
void shouldCreateOrder() {
    // Mock konfigurieren
    when(paymentService.processPayment(any())).thenReturn(PaymentResult.success());
    
    // Test ausführen
    Order order = orderService.createOrder(orderRequest);
    
    assertThat(order.getStatus()).isEqualTo(OrderStatus.CONFIRMED);
}

🎯 Assertions – „Was wird geprüft?“

Assertion (Behauptung)

Was es ist: Eine Aussage die in einem Test wahr sein muss
Einfach gesagt: „Ich behaupte dass X gleich Y ist“
Beispiel: assertThat(result).isEqualTo(expectedResult)

AssertJ vs. Standard Assertions

Standard (schwer lesbar):

assertEquals(5, calculator.add(2, 3));
assertTrue(user.isActive());

AssertJ (gut lesbar):

assertThat(calculator.add(2, 3)).isEqualTo(5);
assertThat(user.isActive()).isTrue();

📈 Qualitäts-Metriken

Test Quality (Test-Qualität)

Was es ist: Wie gut deine Tests tatsächlich Bugs finden
Einfach gesagt: „Sind meine Tests nützlich oder nur Zeitverschwendung?“
Problem: Hohe Coverage ≠ hohe Quality!

Mutation Score (Mutations-Punktzahl)

Was es ist: Prozentsatz der Code-Mutationen die von Tests erkannt werden
Einfach gesagt: „Wie viele künstliche Bugs erkennen meine Tests?“
Beispiel: 90% Mutation Score = Tests erkennen 90% aller eingebauten Fehler

So funktioniert’s:

// Original Code:
if (age >= 18) return "adult";

// Mutation (künstlicher Bug):
if (age > 18) return "adult";   // >= wurde zu >

// Guter Test würde diesen Bug erkennen
// Schlechter Test würde ihn übersehen

Flaky Test (Wackeliger Test)

Was es ist: Test der manchmal grün, manchmal rot ist (ohne Code-Änderung)
Einfach gesagt: „Test-Roulette – niemand weiß ob er durchgeht“
Ursachen: Timing-Probleme, zufällige Daten, externe Dependencies


🔧 Test-Tools & Frameworks

JUnit

Was es ist: Das Standard-Test-Framework für Java
Einfach gesagt: Die Grundausstattung zum Testen in Java
Erkennungszeichen: @Test Annotation

AssertJ

Was es ist: Bibliothek für lesbare Test-Assertions
Einfach gesagt: Macht Test-Prüfungen verständlicher
Erkennungszeichen: assertThat().isEqualTo()

Mockito

Was es ist: Framework zum Erstellen von Mock-Objekten
Einfach gesagt: Hilft beim Erstellen von Fake-Objekten für Tests
Erkennungszeichen: @Mock, when().thenReturn()

Testcontainers

Was es ist: Echte Docker-Container in Tests verwenden
Einfach gesagt: „Starte eine echte Datenbank für meine Tests“
Vorteil: Realistischere Tests als mit Mocks


🧪 Advanced Testing-Begriffe

Property-Based Testing

Was es ist: Tests mit automatisch generierten Test-Daten
Einfach gesagt: „Test nicht ein Beispiel, sondern hunderte automatisch“
Tool: jqwik für Java
Beispiel: Statt „teste add(2,3)“ → „teste add() mit 1000 zufälligen Zahlen-Paaren“

Contract Testing

Was es ist: Tests die API-Verträge zwischen Services prüfen
Einfach gesagt: „Stelle sicher dass API-Changes andere Services nicht brechen“
Tool: Pact

Test Data Builder

Was es ist: Pattern zum eleganten Erstellen von Test-Objekten
Einfach gesagt: „Fluent API für Test-Daten-Erstellung“

// Statt mühsam:
User user = new User("John", "Doe", "john@test.com", true, 25, Address.builder()...);

// Elegant:
User user = anUser()
    .withName("John", "Doe")  
    .withEmail("john@test.com")
    .aged(25)
    .build();

Chaos Engineering

Was es ist: Absichtlich Probleme in Tests einbauen
Einfach gesagt: „Was passiert wenn die Datenbank langsam wird?“
Ziel: Production-Probleme in Tests simulieren


📊 Test-Pyramide

Test Pyramid (Test-Pyramide)

Was es ist: Empfohlene Verteilung verschiedener Test-Arten
Einfach gesagt: „Viele schnelle Tests, wenige langsame Tests“

        /\
       /  \     E2E Tests (10%)
      /    \    - Langsam, teuer
     /______\   - Browser/UI Tests
    /        \  
   /          \ Integration Tests (20%)
  /            \- API Tests, Service Tests  
 /______________\
Unit Tests (70%) - Schnell, billig, isoliert

Warum diese Verteilung:

  • Unit Tests: Schnell, einfach zu debuggen, günstig
  • Integration Tests: Mittlere Geschwindigkeit, testen Zusammenspiel
  • E2E Tests: Langsam, komplex, aber realistisch

🚨 Häufige Missverständnisse

„100% Coverage = Perfekte Tests“

❌ Falsch! Coverage misst nur „wurde Code ausgeführt“, nicht „wurde sinnvoll getestet“

Beispiel für nutzlose 100% Coverage:

@Test
void testEverything() {
    Calculator calc = new Calculator();
    calc.add(1, 2);        // Code wird ausgeführt
    calc.subtract(5, 3);   // Code wird ausgeführt  
    calc.multiply(2, 4);   // Code wird ausgeführt
    
    // ABER: Keine einzige Assertion! Test ist nutzlos!
}

„Unit Tests sind immer besser als Integration Tests“

❌ Falsch! Beide haben ihre Berechtigung:

  • Unit Tests: Gut für Algorithmus-Logic, Validation
  • Integration Tests: Gut für Workflow-Testing, API-Testing

„Mehr Tests = Bessere Software“

❌ Falsch! Qualität > Quantität. 10 gute Tests > 100 schlechte Tests.


💡 Praktische Tipps

Wann welcher Test-Typ:

Unit Tests für:

  • Business Logic (Berechnungen, Validierungen)
  • Algorithmus-Testing
  • Edge-Case-Testing

Integration Tests für:

  • API-Endpoints
  • Service-Zusammenspiel
  • Datenbank-Interaktionen

E2E Tests für:

  • Critical User Journeys
  • Happy-Path-Szenarien
  • Business-Critical-Workflows

Red Flags bei Tests:

  • Tests ohne Assertions: Nutzlos
  • Tests die nie fehlschlagen: Verdächtig
  • Tests die bei jeder Code-Änderung brechen: Zu spezifisch
  • Tests die 10+ Minuten dauern: Zu komplex

📚 Glossar-Cheat-Sheet

BegriffKurzerklärungBeispiel-Tool
Unit TestTestet eine Komponente isoliertJUnit
MockFake-Objekt für TestsMockito
CoverageProzent des getesteten CodesJaCoCo
AssertionPrüfung im TestAssertJ
AAAArrange-Act-Assert Struktur
Mutation ScoreQualität der Tests messenPIT
Property TestAutomatisch generierte Test-Datenjqwik
Contract TestAPI-Verträge prüfenPact
Chaos TestProbleme simulierenChaos Monkey
Test PyramidEmpfohlene Test-Verteilung

Jetzt sollten Dr. Cassian’s Testing-Posts viel verständlicher sein! 🎯

Fehlt ein Begriff? Schreib’s in die Kommentare!


Tags: #Testing #Glossary #JUnit #TestingBasics #Beginner #Java #TestCoverage #UnitTesting