Testabilità dell'unità del modello di generatore

2

Sto osservando il modello di builder per aiutare a impostare dipendenze e parametri che potrebbero richiedere una logica complessa per una classe. Ma dagli esempi che ho visto, il modello di builder non sembra molto verificabile. Esempio che ho preso da qui :

 public static class Builder {
    private long accountNumber; //This is important, so we'll pass it to the constructor.
    private String owner;
    private String branch;
    private double balance;
    private double interestRate;
    public Builder(long accountNumber) {
        this.accountNumber = accountNumber;
    }
    public Builder withOwner(String owner){
        this.owner = owner;
        return this;  //By returning the builder each time, we can create a fluent interface.
    }
    public Builder atBranch(String branch){
        this.branch = branch;
        return this;
    }
    public Builder openingBalance(double balance){
        this.balance = balance;
        return this;
    }
    public Builder atRate(double interestRate){
        this.interestRate = interestRate;
        return this;
    }
    public BankAccount build(){
        //Here we create the actual bank account object, which is always in a fully initialised state when it's returned.
        BankAccount account = new BankAccount();  //Since the builder is in the BankAccount class, we can invoke its private constructor.
        account.accountNumber = this.accountNumber;
        account.owner = this.owner;
        account.branch = this.branch;
        account.balance = this.balance;
        account.interestRate = this.interestRate;
        return account;
    }
}

Tutte le funzioni restituiscono il builder e impostano i membri privati nella classe builder, quindi è difficile verificare se le funzioni sono corrette. In questo caso, forse va bene perché la logica del setter è molto semplice, quindi non ha bisogno di essere testata. Ma cosa succederebbe se le funzioni dovessero svolgere un lavoro più complesso per impostare il parametro per la classe in costruzione? Ad esempio, supponiamo che la funzione riceva un elenco e debba filtrare e raggruppare alcuni valori per creare un dizionario.

In che modo viene comunemente testato il pattern del builder?

Possibili modi per renderlo più testabile:

  1. Sposta tutta la logica in un'altra classe e il costruttore chiama semplicemente quella classe. Il lato negativo è che rende il builder molto meno utile.

  2. Provalo per deduzione attraverso la classe che si sta costruendo. Ma questo diventa più di un test di integrazione e può diventare molto complesso.

posta roverred 19.11.2018 - 04:30
fonte

1 risposta

8

La responsabilità di un solo editore è chiara: per creare un oggetto, ad esempio, un oggetto BankAccount . Il test finale per la correttezza di questo compito è lo stato finale di tale oggetto, il modo in cui il builder funziona internamente è un dettaglio di implementazione che non dovrebbe essere testato.

Quindi il modo semplice per testare un costruttore è chiamando i suoi metodi e controllando l'output del metodo build . Sono sicuro che nel tuo esempio la BankAccount ha "getter" pubblici per ogni membro interessante, quindi il loro contenuto dovrebbe essere molto semplice da convalidare in un test.

But what if the functions need to do more complex work to setup the parameter for the class being built?

Dipende da cosa significa "lavoro più complesso". A volte è sufficiente aggiungere altri test. Una copertura del codice e / o un'analisi della copertura della filiale potrebbero aiutare a scegliere quei test. Quando il costruttore stesso usa un algoritmo molto complesso per fare il suo lavoro, quell'algoritmo complesso forse vale una classe a sé stante, che può quindi essere testato unitamente da solo. Ma non vorrei sottolineare questo approccio fino a quando non è veramente richiesto.

E al tuo commento:

one issue I see with trying to test the final state through the built class's members, is that it means those members have to be public or have getters

Lo stato interno di qualsiasi oggetto significativo è quasi sempre in qualche modo accessibile dalla lettura:

  • direttamente attraverso i getter pubblici

  • o indirettamente influenzando in qualche modo il comportamento di altri metodi pubblici

Altrimenti, lo stato interno sarebbe superfluo. Quindi, guardando l'interfaccia pubblica dell'oggetto costruito, troverai normalmente un modo per convalidare il contenuto.

    
risposta data 19.11.2018 - 05:09
fonte

Leggi altre domande sui tag