Come dovresti guardare i membri protetti dai test unitari usati dalla classe base astratta?

1

Ho le seguenti classi che desidero scrivere test unitari per:

public abstract class BaseClass
{
    public bool IsFooBar(Order order)
    {
        return order.IsNew && IsFooBarOverride(order);
    }

    protected abstract IsFooBarOverride(Order order);
}

public class SimpleDerivedClass : BaseClass
{
    protected override bool IsFooBarOverride(Order order)
    {
        // Return if the order is with a credit card.
    }
}

public class ComplexDerivedClass : BaseClass
{
    protected override bool IsFooBarOverride(Order order)
    {
        // Return a very complex statement
        // If the order is for a new customer
        // in New York, with an order amount of $500 or more
        // and has at opted for email subscriptions.
    }
}

Il problema che sto incontrando è che le mie classi derivate contengono la maggior parte della mia logica per determinare il valore di ritorno di IsFooBar(Order order) . Voglio testare questa logica per assicurarmi che sia corretta. Ho avuto l'impressione che dovresti testare solo l'API pubblica di una classe, che è IsFooBar(Order order) , che appartiene alla classe base.

  • Devo ridisegnare la struttura della mia classe contrassegnando IsFooBar virtuale e spero che altri sviluppatori del team usino base.IsFooBar(order) come parte della loro dichiarazione di ritorno?

  • Devo lasciare la struttura della mia classe in intatta e testare le variazioni del metodo IsFooBar(Order order) per classe derivata come metodo per testare la logica nella classe protetta?

posta michael 09.11.2015 - 20:23
fonte

3 risposte

1

Considerando i tuoi dubbi, direi che la scelta di risolvere questo con l'ereditarietà potrebbe essere l'approccio sbagliato.

Forse la composizione sarebbe più appropriata in questo caso? È difficile dirlo senza conoscere i requisiti.

Per rispondere alla domanda, purché il metodo template sia la strada da percorrere, prova per classe derivata.

    
risposta data 09.11.2015 - 22:11
fonte
0

I was under the impression that you should only test the public API of a class, which is IsFooBar(Order order), which belongs to the base class.

Non proprio.

Questo metodo è protetto e quindi è disponibile solo per sottoclassi.
OK, è accessibile al di fuori della classe (in una certa misura), ma certamente non è "pubblico".

... my derived classes contain the majority of my logic for determining the return value of IsFooBar(Order order). I want to test this logic to ensure it is proper.

Poiché l'implementazione di questi metodi sovrascritti è ciò che devi testare, scrivi test per le classi concrete (io, per esempio, non so come testare un metodo di istanza su una classe astratta, perché non è possibile creare un'istanza di tale classe, quindi, da un punto di vista puramente pratico, avere per lavorare con (cioè testare) le sottoclassi.

Se la maggior parte del codice si trovava in un'implementazione [astratta] della classe base di un determinato metodo, si potrebbe prendere in considerazione la scrittura di una sottoclasse [concreta] esclusivamente a scopo di test.

    
risposta data 10.11.2015 - 13:11
fonte
0

A seconda del framework di test dell'unità, puoi scrivere una classe di test di base astratta che conterrà asserzioni su cosa dovrebbe fare la tua classe di produzione astratta.

Tutte le sottoclassi di quella classe di test di base eseguiranno automaticamente questi test "parent" così come ogni altro test relativo al loro concreto sistema in prova specifico.

Per generare il sistema in prova, puoi ricorrere a un metodo di fabbrica (o alla proprietà di fabbrica).

Esempio con NUnit:

[TestFixture]
public abstract class BaseTest
{
    protected abstract BaseClass Sut { get; }

    [Test]
    public void An_old__order_should_never_be_FooBar()
    {
        var result = Sut.IsFooBar(new Order {IsNew = false});
        Assert.IsFalse(result, "An old Order should never be FooBar no matter the concrete implementation");
    }
}

public class SimpleDerivedClassTest : BaseTest
{
    protected override BaseClass Sut { get { return new SimpleDerivedClass(); } }

    // Your other, SimpleDerived-specific tests here
}

public class ComplexDerivedClassTest : BaseTest
{
    protected override BaseClass Sut { get { return new ComplexDerivedClass(); } }

    // Your other, ComplexDerived-specific tests here
}

Come nota a margine, nell'esempio specifico che hai scelto potrebbe non sembrare così facile determinare quali asserzioni valgono in tutte le circostanze e dovrebbero quindi andare nella classe di test di base. Ma in realtà è piuttosto banale (tutti gli !IsNew degli ordini dovrebbero essere !FooBar ...)

    
risposta data 10.11.2015 - 16:15
fonte

Leggi altre domande sui tag