Domanda

Sto cercando di trovare un modo per falsificare il risultato di un metodo chiamato dall'interno di un altro metodo.

Ho un metodo "LoadData" che chiama un helper separato per ottenere alcuni dati e poi li trasformerà (sono interessato a testare il risultato trasformato).

Quindi ho un codice come questo:

public class MyClass(){
  public void LoadData(){
    SomeProperty = Helper.GetSomeData();
 }
 public object SomeProperty {get;set;}
}

Voglio avere un risultato noto dal metodo Helper.GetSomeData().Posso utilizzare un framework beffardo (ho un'esperienza piuttosto limitata con Rhino Mocks ma sono aperto a qualsiasi cosa) per forzare un risultato atteso?Se é cosi, come?

*Modifica: sì, come previsto, non sono riuscito a ottenere l'hack che volevo, dovrò trovare un modo migliore per impostare i dati.

È stato utile?

Soluzione

Per quanto ne so, dovresti creare un'interfaccia o una classe astratta di base per l'oggetto Helper.Con Rhino Mocks puoi quindi restituire il valore che desideri.

In alternativa, puoi aggiungere un sovraccarico per LoadData che accetta come parametri i dati che normalmente recuperi dall'oggetto Helper.Questo potrebbe anche essere più semplice.

Altri suggerimenti

Hai un problema lì.Non so se questo è uno scenario semplificato del tuo codice, ma se la classe Helper viene utilizzata in questo modo, il tuo codice non è testabile.Innanzitutto, la classe Helper viene utilizzata direttamente, quindi tu non posso sostituirlo con una finta.In secondo luogo, stai chiamando un metodo statico.Non conosco C#, ma in Java tu non è possibile sovrascrivere i metodi statici.

Dovrai eseguire un po' di refactoring per poter iniettare un oggetto fittizio con un metodo GetSomeData() fittizio.

In questa versione semplificata del tuo codice è difficile darti una risposta diretta.Hai alcune opzioni:

  • Crea un'interfaccia per la classe Helper e fornisci al client un modo per inserire l'implementazione Helper nella classe MyClass.Ma se Helper è davvero solo una classe di utilità, non ha molto senso.
  • Crea un metodo protetto in MyClass chiamato getSomeData e fallo chiamare solo Helper.LoadSomeData.Quindi sostituisci la chiamata a Helper.LoadSomeData in LoadData con for getSomeData.Ora puoi simulare il metodo getSomeData per restituire il valore fittizio.

Fai attenzione a creare semplicemente un'interfaccia per la classe Helper e iniettarlo tramite il metodo.Ciò può esporre i dettagli di implementazione.Perché un cliente dovrebbe fornire un'implementazione di a utilità classe per chiamare un'operazione semplice?Ciò aumenterà la complessità dei client MyClass.

Consiglierei di convertire quello che hai in qualcosa del genere:

public class MyClass()
{
    private IHelper _helper;

    public MyClass()
    {
        //Default constructor normal code would use.
        this._helper = new Helper();
    }

    public MyClass(IHelper helper)
    {
        if(helper == null)
        {
            throw new NullException(); //I forget the exact name but you get my drift ;)
        }
        this._helper = helper;
    }

    public void LoadData()
    {
        SomeProperty = this._helper.GetSomeData();
    }
    public object SomeProperty {get;set;}
}

Ora la tua classe supporta ciò che è noto come inserimento delle dipendenze.Ciò ti consente di iniettare l'implementazione della classe helper e garantisce che la tua classe dipenda solo dall'interfaccia.Quando lo prendi in giro, sappi che devi semplicemente creare un mock che utilizza l'interfaccia IHelper e passarlo al costruttore e la tua classe lo utilizzerà come se fosse la vera classe Helper.

Ora, se sei bloccato a utilizzare la classe Helper come classe statica, ti suggerisco di utilizzare un modello proxy/adattatore e di racchiudere la classe statica con un'altra classe che supporti l'interfaccia IHelper (che dovrai anche creare).

Se a un certo punto desideri fare un ulteriore passo avanti, potresti rimuovere completamente l'implementazione Helper predefinita dalla classe rivista e utilizzare i contenitori IoC (Inversion of Control).Se questo è nuovo per te, ti consiglio di concentrarti prima sui fondamenti del motivo per cui vale tutta questa seccatura extra (è IMHO).

I tuoi unit test assomiglieranno a questo pseudo-codice:

public Amazing_Mocking_Test()
{
    //Mock object setup
    MockObject mockery = new MockObject();
    IHelper myMock = (IHelper)mockery.createMockObject<IHelper>();
    mockery.On(myMock).Expect("GetSomeData").WithNoArguments().Return(Anything);

    //The actual test
    MyClass testClass = new MyClass(myMock);
    testClass.LoadData();

    //Ensure the mock had all of it's expectations met.
    mockery.VerifyExpectations();
}

Sentiti libero di commentare se hai domande.(A proposito, non ho idea se questo codice funzioni, l'ho appena digitato nel mio browser, sto principalmente illustrando i concetti).

Potresti voler esaminare Typemock Isolator, che può "falsificare" le chiamate ai metodi senza costringerti a rifattorizzare il tuo codice.Sono un dev in quella società, ma la soluzione è praticabile se si desidera scegliere di non modificare il tuo design (o costretto a non cambiarlo per la testabilità) è su www.typemock.com

Roy Blog:ISerializable.com

Sì, un framework beffardo è esattamente quello che stai cercando.Puoi registrare/organizzare il modo in cui desideri che determinate classi derise/stubbate ritornino.

Rhino Mocks, Typemock e Moq sono tutte buone opzioni per farlo.

Il post di Steven Walther sull'utilizzo di Rhino Mocks mi ha aiutato molto quando ho iniziato a giocare con Rhino Mocks.

Vorrei provare qualcosa del genere:

public class MyClass(){
  public void LoadData(IHelper helper){
    SomeProperty = helper.GetSomeData();
 }

In questo modo puoi simulare la classe helper utilizzando ad esempio MOQ.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top