Evitare di esporre le proprietà al fine di soddisfare il test unitario

1

Uso l'injection dependency per fornire una delle mie classi (SomethingManager) con qualcosa di cui ha bisogno (SomethingEngine). Nel costruttore di SomethingManager ho impostato alcune proprietà su SomethingEngine. SomethingManager quindi espone un insieme di metodi che racchiudono le chiamate a SomethingEngine e alcuni piccoli bit di logica. Vorrei testare unitamente il mio costruttore per testare la logica delle proprietà che ho impostato inizialmente e anche per garantire il corretto le proprietà sono impostate. Per esaminare i risultati dei miei test, sto cercando di esporre un get accessor a ISomethingEngine su SomethingManager ma questa non sembra una buona soluzione.

Quale è un modo migliore per farlo?

private IEngine _engine;
public Manager(IEngine engine)
{
    _engine = engine;
    _engine.Prop1 = "a"; //etc
}

Ora per testare ho davvero bisogno di rendere pubblico IEngine (o almeno interno) e contrassegnarlo come visibile per il mio progetto di test dell'unità

    
posta user48408 31.07.2017 - 16:01
fonte

4 risposte

4

Provare l'unità sotto test, simulare o spegnere il resto.

In questo caso si desidera testare il costruttore SomethingManager. In tal caso, passeresti un finto SomethingEngine. Registra nel simulatore SomethingEngine ciò che SomethingManager chiama su di esso, quindi verifica che siano state fatte le giuste chiamate.

    
risposta data 31.07.2017 - 16:07
fonte
0

Mi sembra che tu stia testando le cose sbagliate.

I test dovrebbero verificare che, dato un determinato input, si ottenga l'output corretto. Come una data funzione arriva ad un output corretto è (per lo più) irrilevante. 1 Supponiamo che la tua classe SomethingManager assomigli a questa:

public class SomethingManager
{
    //...
    public int DoFoo(int x) { ... }
    //...
}

Diciamo che quanto segue dovrebbe essere vero per DoFoo

Input | Output
--------------
1     | 5
2     | 6
3     | 7

Una possibile implementazione di DoFoo sarebbe questa:

public int DoFoo(int x)
{
    if (x == 1) return 5;
    if (x == 2) return 6;
    return 7;
}

O potresti fare questo:

public int DoFoo(int x)
{
    return x + 4;
}

Entrambe le implementazioni raggiungono il comportamento desiderato, quindi entrambe le implementazioni di DoFoo soddisfano il contratto e funzionano come previsto (come definito dai 3 input / output di cui sopra). Che è corretto? Dipende da cosa stai cercando di ottenere. Ma se il modo in cui realizzi il tuo obiettivo cambia per qualsiasi motivo, i test dovrebbero ancora passare.

Quindi è davvero importante sapere che il tuo costruttore imposta una proprietà su una dipendenza? Dovrei sperare di no. Sembra essere più di testare "come funziona" piuttosto che "cosa dovrebbe fare".

1 Potresti progettare test per coprire casi di angoli / bordi di una determinata implementazione, ma se l'implementazione cambia, quei test sono ancora validi.

    
risposta data 31.07.2017 - 17:04
fonte
0

Considera di impostare SomethingEngine proprietà in un metodo factory per SomethignManager e di passarlo configurato al costruttore. Questo separa la configurazione SomethingEngine dalla costruzione SomethingManager , che consente di testare la configurazione SomethingEngine separatamente.

Ad esempio:

class Manager {
    private IEngine _engine;

    //private constructor to allow only properly configured engines
    Manager(IEngine engine) {
        _engine = engine;
    }

    public void ConfigureEngine(IEngine engine) {
        engine.Prop1 = "a";
        //etc
    }

    public static Manager Create(IEngine engine) {
        ConfigureEngine(engine);
        return new Manager(engine);
    }
}

Ciò consente all'unità di testare il metodo ConfigureEngine .

    
risposta data 31.07.2017 - 18:23
fonte
0

Scrivi uno stub conforme all'interfaccia IEngine . Puoi aggiungere tanti accessors allo stub che desideri. Quindi iniettare lo stub. Prova a vedere se Manager chiama lo stub come ti aspetti.

class TestEngine : IEngine
{
    public string Prop1 { get; set; } //You can do this even if get isn't in the interface
}

//Arrange
var e = new TestEngine();

//Act
var m = new Manager(e);

//Assert
Assert.AreEqual("a", e.Prop1);
    
risposta data 31.07.2017 - 23:36
fonte

Leggi altre domande sui tag