Domanda

Abbi pazienza, sono nuovo di NUnit. Vengo dalla terra di Rails, quindi parte di questo è nuovo per me.

Ho una riga di codice simile a questa:

var code = WebSiteConfiguration.Instance.getCodeByCodeNameAndType("CATALOG_Brands_MinQty", item.Catalog);

Sto cercando di deriderlo, in questo modo (supponiamo che code sia già inizializzato):

var _websiteConfigurationMock = new DynamicMock(typeof(WebSiteConfiguration));
_websiteConfigurationMock.ExpectAndReturn("getCodeByCodeNameAndType", code);

Quando eseguo il debug del test, getCodeByCodeNameAndType restituisce null , anziché il code previsto. Cosa sto sbagliando?

Versione NUnit: 2.2.8

È stato utile?

Soluzione

Un DynamicMock crea un nuovo oggetto in memoria che rappresenta l'interfaccia o la classe marshallable (eredita da MarshalByRef) che si desidera deridere.

Prova questo:

var _websiteConfigurationMock = new DynamicMock(typeof(WebSiteConfiguration));
_websiteConfigurationMock.ExpectAndReturn("getCodeByCodeNameAndType", code);
WebSiteConfiguration conf = (WebSiteConfiguration)_websiteConfigurationMock.MockInstance;
var x = conf.getCodeByCodeNameAndType("CATALOG_Brands_MinQty", item.Catalog);

Nota che la terza riga non funzionerà a meno che WebSiteConfiguration non erediti da MarshalByRef.

Quello che fai di solito è deridere un'interfaccia e ottenere un nuovo oggetto che implementa questa interfaccia, ma si comporta nel modo in cui l'hai configurato, senza dover andare e creare un tipo concreto per esso, quindi non lo sono del tutto sicuro che ciò che stai facendo funzionerà a meno che tu non utilizzi un migliore framework di isolamento, come TypeMock in grado di intercettare chiamate a metodi / proprietà statici in oggetti esistenti.

Altri suggerimenti

Mi dispiace, ma non ho mai usato NUnit.Mocks - ma ho una certa esperienza con NMock e Moq [che, a proposito, lo consiglio vivamente]. In genere, si utilizza una libreria beffarda per generare proxy per le definizioni di interfaccia e presumo che NUnit.Mocks funzioni allo stesso modo.

Pertanto, se desideri deridere il tuo singleton, probabilmente dovrai fare quanto segue,

a. Crea un'interfaccia, ad esempio

// All methods you would like to mock from this class, should 
// be members of this interface
public interface IWebSiteConfiguration
{
    // Should match signature of method you are mocking
    CodeType getCodeByCodeNameAndType (
        string codeString, 
        CatalogType catalogType);
}

b. & Quot; Implementare " Interfaccia

// You've already written the method, interface matches signature,
// should be as easy as slapping interface on class declaration
public class WebSiteConfiguration : IWebSiteConfiguration { }

c. Utilizza l'interfaccia

va bene, quindi passo c. è dove sarà la maggior parte del tuo lavoro. Logicamente, se stai deridendo il tuo singleton, stai effettivamente testando l'unità del consumatore [che hai lasciato fuori dal tuo campione]. Per c. è sufficiente aggiungere un parametro al ctor del consumatore o aggiungere una proprietà accessibile pubblicamente di tipo "IWebSiteConfiguration", quindi fare riferimento internamente al membro dell'istanza e richiamare i metodi su questa nuova interfaccia. Considera questo,

è stato

public class MyClass
{
    public MyClass () { }

    public void DoSomething ()
    {
        // bad singleton! bad boy! static references are bad! you
        // can't change them! convenient but bad!
        code = WebSiteConfiguration.Instance.getCodeByCodeNameAndType (
            "some.string", 
            someCatalog)
    }
}

diventa

public class MyClass
{
    private readonly IWebSiteConfiguration _config = null;

    // just so you don't break any other code, you can default
    // to your static singleton on a default ctor
    public MyClass () : this (WebSiteConfiguration.Instance) { }

    // new constructor permits you to swap in any implementation
    // including your mock!
    public MyClass (IWebSiteConfiguration config) 
    {
        _config = config;
    }

    public void DoSomething ()
    {
        // huzzah!
        code = _config.getCodeByCodeNameAndType ("some.string", someCatalog)
    }
}

Nel test unitario, creare la simulazione, passare un riferimento della simulazione al consumatore e testare il consumatore.

[Test]
public void Test ()
{
    IWebSiteConfiguration mockConfig = null;
    // setup mock instance and expectation via
    // NUnit.Mocks, NMock, or Moq

    MyClass myClass = new MyClass (mockConfig);
    myClass.DoSomething ();

    // verify results
}

Questo serve anche come introduzione pratica a Dependency Injection [DI]. È semplicemente la pratica di trasmettere o "iniettare" riferimenti di servizi [ad esempio la classe di configurazione del tuo sito Web] al consumatore, piuttosto che fare in modo che il consumatore invochi il servizio direttamente [ad esempio tramite una classe singleton statica].

Spero che questo aiuti :)

Sembra che ci sia una sorta di soluzione per questo usando la riflessione, o forse ho capito male.

È discusso qui: http: //www.geekbeing .com / 2010/05/23 / how-to-unit-test-Singleton-mod-in-c

Potrebbe davvero funzionare?

public class TestableSingleton : SingletonClass
{
  public TestableSingleton ()
  {
    FieldInfo fieldInfo = typeof(SingletonClass)
        .GetField("_instance",
        BindingFlags.Static | BindingFlags.NonPublic);
    fieldInfo.SetValue(Instance, this);
  }
}

Progetto disponibile su https://github.com/rbabreu/TestableSingleton

In realtà non sono riuscito a compilarlo su Visual Studio poiché SingletonClass avrebbe un costruttore privato. Se qualcuno dovesse farlo funzionare, sarebbe bello evitare il sovraccarico del modello di adattatore.

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