Code Smell 299 - Como corrixir as configuracións de proba sobrecargadas

por Maximiliano Contieri7m2025/05/10
Read on Terminal Reader

Demasiado longo; Ler

A configuración inundada que só se usa parcialmente fai que os teus test sexan máis combinados e máis difíciles de entender.
featured image - Code Smell 299 - Como corrixir as configuracións de proba sobrecargadas
Maximiliano Contieri HackerNoon profile picture

Cando a configuración da proba é maior que a proba real

TL;DR: unha configuración inundada que só se usa parcialmente fai que os teus test sexan máis combinados e máis difíciles de entender.

TL;DR: unha configuración inundada que só se usa parcialmente fai que os teus test sexan máis combinados e máis difíciles de entender.

Problemas

  • Coupling
  • lexibilidade
  • Perda de tempo de execución
  • Configuración dun contexto erróneo
  • Test de dependencia oculta
  • Manutención máis difícil
  • Suite de probas Brittle
  • Confusión dependencia
  • Execución máis lenta
  • Contexto erróneo

Solucións

  1. Creación de métodos de configuración enfocados
  2. Aplica fixacións de proba específicas
  3. Crear configuracións mínimas
  4. Implementación de métodos de proba de fábrica

Recuperación ️

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

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

O contexto

Cando escribe probas, pode crear un gran método de configuración que inicia varios obxectos.


Se só unha proba usa todos estes obxectos, mentres que outras probas usan só un pequeno subconxunto, crea un superconxunto innecesario.


Este problema común ocorre cando espera que futuras probas poidan necesitar unha configuración extensa, ou cando continúa engadindo a unha configuración existente sen avaliar o que realmente é necesario.


As probas son máis difíciles de entender porque conteñen contexto irrelevante e máis lentas de executar porque se inician obxectos que non se usan.

Modelo de código

equivocado 🙂

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());
  }
}

Xusto 🙂

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);
  }
}

Detección

  • [x] Semi-automático

Pode detectar este cheiro comparando o que está configurado nos métodos de configuración contra o que se usa en cada proba.


Buscar probas que utilicen menos do 50% dos obxectos inicializados.


As ferramentas de cobertura de código poden axudar a identificar obxectos de configuración non utilizados mostrando que partes da configuración non se executan por certas probas.


Se vostede se atopa escribindo condicionais na configuración para crear diferentes contextos, é un sinal claro de que necesita unha configuración específica de proba no seu lugar.

Xogos ️

  • Probas

Nivel

  • [x] Intermediarios

Por que é tan importante a bijeción ️

Cada proba debe reflectir un escenario específico do mundo real.


As configuracións inchadas rompen esta claridade, o que dificulta ver o que está a ser probado e aumenta a probabilidade de erros.


Esta desfeitaBixeciónFacer que as probas sexan máis difíciles de comprender porque non se pode determinar que aspectos da configuración son críticos para a proba e que son só ruídos.


Cando unha proba fracase, pasarás máis tempo investigando dependencias que poden non ser relevantes para o fracaso.


A proba faise máis fráxil xa que os cambios a obxectos non utilizados aínda poden romper as probas se eses obxectos participan no proceso de configuración.

A miña xeración

Os xeradores de código de IA a miúdo crean este cheiro cando xeran equipos de proba abrangentes que intentan cubrir todos os escenarios posibles.


Priorizan a completude sobre o foco, resultando en métodos de configuración inchados que inician máis obxectos do que é necesario para probas individuais.

A súa detección

A IA pode detectar este cheiro con instrucións sinxelas como "Optimizar a miña configuración de proba só para incluír o que se necesita para cada proba".


As modernas ferramentas de IA poden comparar o código de configuración co uso do método de proba e suxerir refactorings dirixidos, separando a configuración compartida da configuración específica de probas.

Proba con eles!

Lembra: os asistentes de IA cometen moitos erros

Prompt suxerido: romper as probas e a configuración

Prompt suxerido: romper as probas e a configuración

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

Perplexidade

Perplexidade

piloto

piloto

ximielgos

ximielgos

profundidade

profundidade

O obxectivo é

O obxectivo é

Grúas

Grúas

Quenda

Quenda

Conclusión

As configuracións de proba sobrecargadas que inicializan obxectos necesarios só por uns poucos ensaios fan que a súa suite de ensaios sexa máis difícil de entender e manter.

Cando crea configuracións focalizadas que conteñan só o que precisa cada proba, mellora a claridade, a velocidade e a fiabilidade das súas probas.

Lembre que as probas teñen como obxectivo documentar o comportamento a través de exemplos eSubstituír comentarios.


Demasiado contexto irrelevante fai que eses exemplos sexan menos lexibles.Probas limpas contan unha historia clara sen distraccións innecesarias.

Relacións

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

Máis información

Disclaimer

Os cheiros son meusOpinión.

Créditos

Imaxe porMartiño SimónqueUnsplash


Se ten que crear unha gran cantidade de estrutura antes dunha proba, quizais está probando a través de demasiadas capas

Se ten que crear unha gran cantidade de estrutura antes dunha proba, quizais está probando a través de demasiadas capas

Xesús Shore


Este artigo forma parte da serie CodeSmell.


Trending Topics

blockchaincryptocurrencyhackernoon-top-storyprogrammingsoftware-developmenttechnologystartuphackernoon-booksBitcoinbooks