Metodi statici e testabilità

0

Ho un servizio di applicazione che restituisce l'entità con il suo numero di registrazione

public Entity FindByRegNumber(string number)
{
    if (!RegNumber.IsValid(number))
    {
        return null;
    }

    var regNumber = new RegNumber(regNumber);
    return repository.FindBy(regNumber);
}

Qui RegNumber è un oggetto valore e ha il metodo statico IsValid che verifica che la stringa rappresenti correttamente il numero di registrazione. Questo metodo viene utilizzato anche all'interno del costruttore, ma, se la stringa non è valida, il costruttore genera InvalidOperationException .

Se il metodo IsValid apparteneva a qualche dipendenza iniettata, potevo semplicemente verificare nel mio test che fosse stato chiamato IsValid (un tipo di test della casella bianca). Ora devo testare FindByRegNumber ripetendo tutto l'input usato per testare il metodo IsValid (test black box).

Sembra che l'unico motivo per sbarazzarsi del metodo statico è rendere i test più facili. Non diminuisce nemmeno l'accoppiamento durante la chiamata a FullRegistrationNumber di permanenze del costruttore.

Un altro approccio è introdurre una factory FullRegistrationNumberCreator' which could abstract away both validation and construction of FullRegistrationNumber ', ma sembra un overkill e overengineering.

È qui una soluzione corretta?

    
posta Pavel Voronin 04.04.2017 - 10:13
fonte

2 risposte

4

La prima cosa da sottolineare è che non concordo con il modo in cui testate la validità e create l'istanza di RegNumber .

Lo progetterei in modo che ci sia solo un modo per creare un'istanza di RegNumber e che includa anche un controllo di validità.

Ad esempio qualcosa come

public static bool RegNumber.TryParse(string number, out RegNumber regNumber)
{
  //...
}

Quindi, per creare una nuova istanza di RegNumber , devi chiamare questo metodo. Questo introduce quindi un vincolo strutturale, che se qualcosa usa il tipo RegNumber , ne sta usando uno valido.

Quindi, prendo l'approccio pragmatico e dico che il codice che presenti non ha alcuna logica interessante da testare. Ed è sufficiente scrivere due test di integrazione di alto livello. Per prima cosa controllare con un numero di registrazione valido, in secondo luogo con un numero di registrazione non valido. Non è necessario testare di nuovo l'invalidazione della registrazione completa.

    
risposta data 04.04.2017 - 14:52
fonte
3

Vorrei estrarre il concetto di RegNumberValidator in una classe a sé stante.

La sua istanza potrebbe avere un metodo virtual bool IsValid(string) , tale da poter essere sovrascritto per il test e anche per le classi derivate che richiedono passaggi di convalida aggiuntivi.

Se preferisci una classe / metodo statico, puoi comunque utilizzare un trucco descritto da M. Feathers nel suo "Working with Legacy Code", ad es.

public static class RegNumberValidator
{
    private IRegNumberValidator _instance = new NonstaticRegNumberValidator();

    public void SetInstanceForTesting(IRegNumberValidator testInstance)
    {
        _instance = testInstance;
    }

    public bool IsValid(string regNumber)
    {
        return(_instance.IsValid(regNumber));
    }
}

Nota: alcune persone pensano che questo sia un trucco che dovrebbe essere applicato solo nei casi di codice legacy - perché non si può andare avanti senza hack. Secondo me, è un modello valido.

    
risposta data 04.04.2017 - 10:39
fonte

Leggi altre domande sui tag