Code Smell 299 - So beheben Sie überlastete Test-Einstellungen

von Maximiliano Contieri7m2025/05/10
Read on Terminal Reader

Zu lang; Lesen

Eine überfüllte Konfiguration, die nur teilweise verwendet wird, macht Ihre Tests gekoppelter und schwieriger zu verstehen.
featured image - Code Smell 299 - So beheben Sie überlastete Test-Einstellungen
Maximiliano Contieri HackerNoon profile picture

Wenn Ihr Test-Setup größer ist als der tatsächliche Test

TL;DR: Eine überwältigende Einrichtung, die nur teilweise verwendet wird, macht Ihre Tests gekoppelter und schwieriger zu verstehen.

TL;DR: Eine überwältigende Einrichtung, die nur teilweise verwendet wird, macht Ihre Tests gekoppelter und schwieriger zu verstehen.

Probleme

  • Coupling
  • Lesbarkeit
  • Verlorene Ausführungszeit
  • Irreführender Setup-Kontext
  • Hidden Test Abhängigkeiten
  • härtere Wartung
  • Die Brittle Test Suite
  • Verwirrende Abhängigkeiten
  • Langsamere Exekutive
  • Irreführender Kontext

Lösungen

  1. Erstellen von fokussierten Setup-Methoden
  2. Test-spezifische Fixierungen anwenden
  3. Minimale Setups erstellen
  4. Implementierung von Fabrik-Testmethoden

Reaktionen ️

https://hackernoon.com/improving-the-code-one-line-at-a-time

https://maximilianocontieri.com/refactoring-011-replace-comments-with-tests

Zusammenhang

Wenn Sie Tests schreiben, können Sie eine große Setup-Methode erstellen, die verschiedene Objekte initialisiert.


Wenn nur ein Test alle diese Objekte verwendet, während andere Tests nur eine kleine Untergruppe verwenden, erstellen Sie unnötige Überschüsse.


Dieses häufige Problem tritt auf, wenn Sie erwarten, dass zukünftige Tests eine umfangreiche Einrichtung benötigen, oder wenn Sie eine bestehende Einrichtung hinzufügen, ohne zu bewerten, was wirklich benötigt wird.


Die Tests sind schwieriger zu verstehen, da sie irrelevanten Kontext enthalten, und langsamer zu führen, weil Sie Objekte initialisieren, die nicht verwendet werden.

Sample Code

Falsch 🙂

public class TVSeriesTest {
  private MovieSeries theEthernaut;
  private List<Character> characters;
  private List<Episode> episodes;
  private User user;
  private UserPreferences preferences;
  private RatingSystem ratingSystem;
  private StreamingService streamingService;
  private List<Review> reviews;
  
  @BeforeEach
  public void setUp() {
    // Create a complex movie series with many characters
    characters = new ArrayList<>();
    characters.add(new Character("Juan Salvo", "Richard Darin"));
    characters.add(new Character("Helen", "Carla Peterson")); 
    characters.add(new Character("Favalli", "Cesar Troncoso")); 
    
    // Create episodes
    episodes = new ArrayList<>();
    episodes.add(
      new Episode("The Snow", 2025, 121));
    episodes.add(
      new Episode("The Hands Strikes Back", 2027, 124)); 
    
    // Create user with preferences
    preferences = new UserPreferences();
    preferences.setPreferredGenre("Science Fiction");
    preferences.setPreferredLanguage("English");
    preferences.setSubtitlesEnabled(true);
    user = new User("JohnDoe", "john@example.com", preferences);
    
    // Create rating system with reviews
    ratingSystem = new RatingSystem(10);
    reviews = new ArrayList<>();
    reviews.add(
      new Review(user, "The Snow", 9, "Classic!"));
    reviews.add(
      new Review(user, "The Hands Strikes Back", 10, "Best one!"));
    ratingSystem.addReviews(reviews);
    
    // Create streaming service
    streamingService = new StreamingService("Netflix");
    streamingService.addMovieSeries("The Eternaut");
    
    // Finally create the movie series with all components
    theEthernaut = 
      new TVSeries("The Ethernaut", characters, episodes);
    theEthernaut.setRatingSystem(ratingSystem);
    theEthernaut.setAvailableOn(streamingService);
    
    // This method is too long. That is another smell
  }
  
  @Test
  public void testTVSeriesRecommendation() {
    // This test uses almost everything from the setup
    RecommendationEngine engine = new RecommendationEngine();
    List<Episode> recommended =
      engine.recommendations(user, theEternaut);
    
    assertEquals(2, recommended.size());
    assertEquals("The Hands Strikes Back",
      recommended.get(0).title());
    // You are testing the recomendation Engine
    // This is not this object's responsibility
  }
  
  @Test
  public void testEpisodeCount() {
    // This test only needs the episodes count
    assertEquals(2, theEthernaut.episodes().size());
  }
  
  @Test
  public void testCharacterLookup() {
    // This test only needs the characters
    // And not the rest of the setup
    Character juan = theEternaut.findCharacterByName("Juan Salvo");
    assertNotNull(juan);
    assertEquals("Juan Salvo", juan.actor());
  }
}

Richtig 🙂

public class TVSeriesTest {
  // No shared setup
  
  @Test
  public void testRecommendation() {
    // Create only what's needed for this specific test
    // And move this test with the behavior
    TVSeries theEternaut = createTheEternautSeries();
    User homer = createUserWithPreferences();
    addReviewsForUser(theEternaut, homer);
    
    RecommendationEngine engine = new RecommendationEngine();
    List<Episode> recommended =
      engine.recommendations(homer, theEternaut);
    
    assertEquals(2, recommended.size());
    assertEquals("The Hands Strikes Back", 
      recommended.get(0).title());
  }
  
  @Test
  public void testEpisodeCount() {
    // Only create what's needed - just the episodes
    TVSeries theEternaut = new TVSeries("The Ethernaut");
    theEternaut.addEpisode(
      new Episode("The Snow", 2025, 121));
    theEternaut.addEpisode(
      new Episode("The Hands Strikes Back", 2027, 124)); 
    
    assertEquals(2, theEternaut.episodes().size());
  }
  
  @Test
  public void testCharacterLookup() {
    // Only create what's needed - just the characters
    TVSeries theEternaut = new TVSeries("The Eternaut");
    theEternaut.addCharacter(
      new Character("Juan Salvo", "Richard Darin"));
    theEternaut.addCharacter(
      new Character("Helen", "Carla Peterson")); 
    
    Character juan = theEternaut.findCharacterByName("Juan Salvo");
    assertNotNull(juan);
    assertEquals("Richard Darin", juan.actor());
  }
  
  // Helper methods for specific test setup needs
  private TVSeries createTheEternautTVSeries() {
    TVSeries series = new TVSeries("The Eternaut");
    series.addEpisode(
      new Episode("The Snow", 2025, 121));
    series.addEpisode(
      new Episode("The Hands Strikes Back", 2027, 124)); 
    return series;
  }
  
  private User createUserWithPreferences() {
    UserPreferences preferences = new UserPreferences();
    preferences.setPreferredGenre("Science Fiction");
    preferences.setPreferredLanguage("English");
    return new User("JohnDoe", "john@example.com", preferences);
  }
  
  private void addReviewsForUser(TVSeries series, User user) {
    RatingSystem ratingSystem = new RatingSystem(10);
    ratingSystem.addReview(
      new Review(user, "The Snow", 9, "Classic!"));
    ratingSystem.addReview(
      new Review(user, "The Hands Strikes Back", 10, "Best one!"));
    series.setRatingSystem(ratingSystem);
  }
}

Erkundung

  • [x] halbautomatisch

Sie können diesen Geruch erkennen, indem Sie vergleichen, was in den Setup-Methoden eingerichtet ist, mit dem, was in jedem Test verwendet wird.


Suchen Sie nach Tests, die weniger als 50% der initialisierten Objekte verwenden.


Code-Coverage-Tools können ungenutzte Setup-Objekte identifizieren, indem sie zeigen, welche Teile der Setup durch bestimmte Tests nicht ausgeführt werden.


Wenn Sie feststellen, dass Sie in der Konfiguration Bedingungen schreiben, um verschiedene Kontexte zu erstellen, ist dies ein klares Zeichen dafür, dass Sie stattdessen eine testspezifische Konfiguration benötigen.

Tags ️

  • Testen

Ebene

  • [x] Zwischenzeit

Warum die Bijection wichtig ist ️

Jeder Test sollte ein spezifisches reales Szenario widerspiegeln.


Überschwemmte Setups brechen diese Klarheit, was es schwierig macht zu sehen, was getestet wird und die Wahrscheinlichkeit von Fehlern erhöht.


Diese gebrochenenBijectionTests werden schwieriger zu verstehen, da Sie nicht bestimmen können, welche Aspekte der Installation für den Test entscheidend sind und welche nur Lärm sind.


Wenn ein Test fehlschlägt, verbringen Sie mehr Zeit damit, Abhängigkeiten zu untersuchen, die für den Fehler möglicherweise nicht relevant sind.


Der Test wird brüchiger, da Änderungen an unbenutzten Objekten immer noch Tests durchbrechen können, wenn diese Objekte am Setup-Prozess teilnehmen.

Die Generation

KI-Code-Generatoren schaffen diesen Geruch oft, wenn sie umfassende Testgeräte generieren, die versuchen, alle möglichen Szenarien zu decken.


Sie priorisieren Vollständigkeit über Fokus, was zu aufgeblähten Setup-Methoden führt, die mehr Objekte initialisieren, als für einzelne Tests erforderlich sind.

Die Erkennung

AI kann diesen Geruch mit einfachen Anweisungen wie "Optimieren Sie meine Test-Setup nur, um zu enthalten, was für jeden Test benötigt wird."


Moderne KI-Tools können den Setup-Code mit der Verwendung von Testmethoden vergleichen und gezielte Refactorings vorschlagen, was die geteilte Einrichtung von der testspezifischen Einrichtung trennt.

Probieren Sie es aus!

Denken Sie daran: AI-Assistenten machen viele Fehler

Vorschlag Prompt: Brechen Sie die Tests und die Installation

Vorschlag Prompt: Brechen Sie die Tests und die Installation

Without Proper Instructions

With Specific Instructions

ChatGPT

ChatGPT

Claude

Claude

Perplexity

Perplexity

Copilot

Copilot

Gemini

Gemini

DeepSeek

DeepSeek

Meta AI

Meta AI

Grok

Grok

Qwen

Qwen

ChatGPT

ChatGPT

Claude

Claude

Verwirrung

Verwirrung

Kinderpilot

Kinderpilot

Gemini

Gemini

DeepSeek

DeepSeek

Ziel ist AI

Ziel ist AI

Groke

Groke

QWEN

QWEN

Schlussfolgerung

Überlastete Test-Setups, die Objekte initialisieren, die nur von wenigen Tests benötigt werden, machen Ihre Test-Suite schwieriger zu verstehen und zu pflegen.

Wenn Sie gezielte Setups erstellen, die nur das enthalten, was jeder Test benötigt, verbessern Sie die Klarheit, Geschwindigkeit und Zuverlässigkeit Ihrer Tests.

Denken Sie daran, dass Tests das Verhalten durch Beispiele undKommentare ersetzen.


Zu viel irrelevanter Kontext macht diese Beispiele weniger lesbar.Reine Tests erzählen eine klare Geschichte ohne unnötige Ablenkungen.

Beziehung

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxv

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xi-sit35t1

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxiii

https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xli

Weitere Informationen

Disclaimer

Code Gerüche sind meineMeinungen.

Kredite

Foto vonMarkus SimonidesistUnsplash


Wenn Sie vor einem Test viel Struktur erstellen müssen, testen Sie möglicherweise zu viele Schichten

Wenn Sie vor einem Test viel Struktur erstellen müssen, testen Sie möglicherweise zu viele Schichten

von James Shore


Dieser Artikel ist Teil der CodeSmell-Serie.


Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks