Unit test di chiamate private, o no

5

Ho questo metodo, che ha più chiamate private: GetConfigStatuses() , ApplyFilters() , GetConfigListInfo() .

Poiché questi non espongono nulla di pubblico, non posso testarli come farei per un pubblico. E non sto cambiando il livello di accesso, sarebbe un odore.

Quindi l'unica cosa che posso effettivamente verificare e dichiarare in questo metodo è la chiamata GetPackages() . Questo è almeno come lo vedo io.

Ma non ne sono sicuro, perché sono abbastanza nuovo da prendere in giro:)

Di seguito è riportato il metodo che sto testando e uno dei miei test.

Le cose sembrano ok? Grazie:)

public IEnumerable<UIConfigListInfo> GetUiConfigs(string segment, UIConfigInfo uiConfigInfo)
{
    try
    {
        var configStatus = string.IsNullOrEmpty(uiConfigInfo.Status) ? "Active" : uiConfigInfo.Status;

        var configListInfoList = new List<UIConfigListInfo>();
        foreach (var currentConfigStatus in GetConfigStatuses(configStatus))
        {
            var filters = ApplyFilters(segment, uiConfigInfo.Name.ToLowerInvariant(), currentConfigStatus.ToLowerInvariant(), uiConfigInfo.Version);

            var packages = _storageRepository.GetPackages(filters, Order.Descending, configStatus).ToList();

            foreach (Package package in packages)
            {
                try
                {
                    //TODO: comment this.
                    var configListInfo = GetConfigListInfo(package, uiConfigInfo.Version, uiConfigInfo.Name, currentConfigStatus);
                    //TODO: comment this.
                    GetConfigDefinition(package.Data, configListInfo);


                    configListInfoList.Add(configListInfo);
                }
                catch (Exception ex)
                {
                    //TODO: log! Throw ?
                }
            }
        }
        return configListInfoList;
    }
    catch (Exception ex)
    {
        //...
    }
}

E il test qui sotto. È importante notare che la mia classe di servizio ha solo una dipendenza pubblica ( IStorageRepository ). Il GetPackages() restituisce un List<Package> .

[TestMethod]
public void TestMethod1()
{
    //Arrange
    var mockStorageRepository = new Mock<IStorageRepository>();
    mockStorageRepository.Setup(s => s.GetPackages(It.IsAny<List<string>>(), Order.Ascending, "Active"));

    var sut = new UIConfigService(mockStorageRepository.Object);

    //Act
    sut.GetUiConfigs("somesegment", new UIConfigInfo { Name = "TestFun" });

    //Assert
    mockStorageRepository.Verify(mock => mock.GetPackages(It.IsAny<List<string>>(), Order.Descending, "Active"), Times.Once);
}
    
posta frostings 13.09.2017 - 09:45
fonte

3 risposte

14

Test unità s verifica il comportamento osservabile pubblico di un'unità di codice.

La distribuzione di questo comportamento a un gruppo di metodi privati è dettaglio dell'implementazione che tu fai test non . Il motivo è che non si vuole fallire il test quando si modificano i dettagli dell'implementazione per qualche motivo, molto probabilmente perché si aggiungono ulteriori comportamenti.

I test invariati sono la prova più affidabile che il comportamento desiderato esiste ancora dopo una modifica al codice di produzione.

    
risposta data 13.09.2017 - 11:50
fonte
2

Aumenterò e sosterrò la risposta completamente opposta .... Se ApplyFilters () ha una logica sufficiente per essere considerata un'unità, allora dovrebbe avere i suoi test unitari che la testano direttamente

Alimentare tutti i casi di test del metodo privato tramite il metodo pubblico rende i test fragili in un modo diverso e più impattante .. se si modifica la logica del metodo pubblico è probabile che si interrompano i test il cui scopo è testare il comportamento il metodo privato. Poiché il numero di metodi privati cresce rapidamente, la modifica del metodo pubblico è incredibilmente dolorosa.

Se una funzione chiave della classe pubblica è chiamare la classe privata, prendere in giro la classe privata e testare in quali casi e con quali argomenti viene chiamato il privato. Quindi, in test separati, verifica che la funzione privata gestisca tali casi.

    
risposta data 13.09.2017 - 14:38
fonte
2

A volte vuoi testare metodi privati.

Esiste un compromesso intrinseco alla granularità di un test. I test per unità di funzionalità più piccole tendono ad essere più facili da scrivere in quanto richiedono meno impostazioni e possono fornire input e ricevere output in modo più diretto. Inoltre possono spesso evitare porzioni della base di codice che si basano su effetti collaterali. Inoltre corrono più velocemente e individuano gli errori. Questi vantaggi sono il motivo per cui scriviamo test unitari in primo luogo.

I test per unità di funzionalità più ampie mettono alla prova la logica dell'applicazione più vicina ai requisiti e fanno meno affidamento sui dettagli di implementazione. Un refactoring ha meno probabilità di richiedere la modifica di un test chiamando un'API di livello superiore rispetto a un test che chiama un'API di basso livello. Inoltre, testano insieme i componenti del programma, in modo che possano trovare problemi con l'interoperabilità. Questi vantaggi sono il motivo per cui scriviamo test di integrazione.

Test unitari e test di integrazione cadono in due punti di un continuum. Questo continuum si estende oltre i test unitari per le funzioni pubbliche fino alle funzioni private, e i suddetti vantaggi e svantaggi dei test unitari si applicano all'estremo per testare queste funzioni. Le funzioni private spesso contengono una logica non banale e spesso implementano le funzionalità direttamente sotto la responsabilità della classe o del modulo, in modo che appartengano a questo. Il test diretto offre i vantaggi dei test unitari: posizione dell'errore semplice, rapida e precisa. Tuttavia, sono i più propensi a soffrire di refactoring.

In pratica mi trovo a scrivere molti di questi test per algoritmi che coinvolgono più passaggi. Un semplice esempio è K-Means, che alterna un passo della media dei vettori e li suddivide in base alla media del passo precedente a cui sono più vicini. Ognuna di queste fasi può essere facilmente testata con le unità, ed è più facile testare ciascun passaggio individualmente che come parte dell'intero algoritmo.

    
risposta data 13.09.2017 - 23:38
fonte

Leggi altre domande sui tag