Cosa succede con i test dei metodi quando quel metodo diventa privato dopo la riprogettazione in TDD?

29

Diciamo che inizio a sviluppare un gioco di ruolo con personaggi che attaccano altri personaggi e quel tipo di cose.

Applicando TDD, faccio alcuni test case per testare la logica all'interno del metodo Character.receiveAttack(Int) . Qualcosa del genere:

@Test
fun healthIsReducedWhenCharacterIsAttacked() {
    val c = Character(100) //arg is the health
    c.receiveAttack(50) //arg is the suffered attack damage
    assertThat(c.health, is(50));
}

Supponiamo che abbia 10 metodi per testare il metodo receiveAttack . Ora aggiungo un metodo Character.attack(Character) (che chiama il metodo receiveAttack ), e dopo alcuni cicli TDD che lo testano, prendo una decisione: Character.receiveAttack(Int) dovrebbe essere private .

Cosa succede con i 10 casi di test precedenti? Dovrei eliminarli? Devo mantenere il metodo public (non penso)?

Questa domanda non riguarda come testare i metodi privati ma come affrontarli dopo una riprogettazione quando si applica TDD

    
posta Héctor 03.10.2017 - 10:50
fonte

3 risposte

52

In TDD, i test servono come documentazione eseguibile del tuo progetto. Il tuo progetto è cambiato, ovviamente anche la tua documentazione!

Si noti che, in TDD, l'unico modo in cui il metodo attack poteva apparire, è il risultato di un test pass fallito. Il che significa che attack viene testato da qualche altro test. Ciò significa che indirettamente receiveAttack è coperto dai test di attack . Idealmente, qualsiasi modifica a receiveAttack dovrebbe interrompere almeno uno dei test di attack .

E se così non fosse, allora c'è funzionalità in receiveAttack che non è più necessaria e non dovrebbe più esistere!

Quindi, poiché receiveAttack è già stato testato con attack , non importa se mantieni o meno i tuoi test. Se il tuo framework di test facilita il test dei metodi privati, e if tu decidi di testare i metodi privati, puoi mantenerli. Ma puoi anche eliminarli senza perdere copertura e sicurezza.

    
risposta data 03.10.2017 - 11:25
fonte
23

Se il metodo è abbastanza complesso da richiedere test, dovrebbe essere pubblico in alcune classi. Quindi ti rifatti da:

public class X {
  private int complexity(...) {
    ...
  }
  public void somethingElse() {
    int c = complexity(...);
  }
}

a:

public class Complexity {
  public int calculate(...) {
    ...
  }
}

public class X {
  private Complexity complexity;
  public X(Complexity complexity) { // dependency injection happiness
    this.complexity = complexity;
  }

  public void something() {
    int c = complexity.calculate(...);
  }
}

Spostare il test corrente per X.complexity su ComplexityTest. Quindi scrivi Xqualcosa prendendo in giro Complessità.

Secondo la mia esperienza, il refactoring verso classi più piccole e metodi più brevi comporta enormi benefici. Sono più facili da capire, più facili da testare e finiscono per essere riutilizzati più di quanto ci si potrebbe aspettare.

    
risposta data 03.10.2017 - 11:32
fonte
6

Say I have 10 methods testing receiveAttack method. Now, I add a method Character.attack(Character) (that calls receiveAttack method), and after some TDD cycles testing it, I make a decision: Character.receiveAttack(Int) should be private.

Qualcosa da tenere a mente qui è che la decisione che stai prendendo è per rimuovere un metodo dall'API . Le cortesie di retrocompatibilità suggerirebbero

  1. Se non hai bisogno di rimuoverlo, lasciatelo nell'API
  2. Se non è necessario rimuoverlo ancora , quindi contrassegnarlo come deprecato e, se possibile, documento quando avverrà la fine della vita
  3. Se hai bisogno di rimuoverlo, allora hai una modifica della versione principale

I test vengono rimossi / o sostituiti quando la tua API non supporta più il metodo. A quel punto, il metodo privato è un dettaglio di implementazione che dovresti essere in grado di rifattorizzare.

A questo punto, si torna alla domanda standard se la suite di test dovesse accedere direttamente alle implementazioni, piuttosto che interagire esclusivamente tramite l'API pubblica. Un metodo privato è qualcosa che dovremmo essere in grado di sostituire senza che la suite di test interferisca con . Quindi mi aspetterei che i test si abbinino ad esso per andare via - o ritirarsi, o spostarsi con l'implementazione su un componente testabile separatamente.

    
risposta data 03.10.2017 - 17:27
fonte

Leggi altre domande sui tag