Question

Ours avec moi, je suis nouveau à NUnit. Je viens du pays des Rails, donc certaines de ces choses sont nouvelles pour moi.

J'ai une ligne de code qui ressemble à ceci:

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

J'essaie de le simuler, comme ceci (supposons que le code soit déjà initialisé):

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

Lorsque je débogue le test, getCodeByCodeNameAndType renvoie null au lieu du code attendu . Qu'est-ce que je fais mal?

Version de NUnit: 2.2.8

Était-ce utile?

La solution

Un DynamicMock crée un nouvel objet en mémoire qui représente l'interface ou la classe marshallable (hérite de MarshalByRef) que vous souhaitez simuler.

Essayez ceci:

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

Notez que la troisième ligne ne fonctionnera que si WebSiteConfiguration hérite de MarshalByRef.

En général, vous vous moquez d'une interface et obtenez un nouvel objet qui implémente cette interface, mais qui se comporte comme vous l'avez configuré, sans avoir à créer de type concret, donc je ne suis pas vous êtes absolument sûr de ce que vous ferez si vous n’utilisez pas un meilleur cadre d’isolation, comme TypeMock, capable d’intercepter les appels de méthodes / propriétés statiques dans des objets existants.

Autres conseils

Je suis désolé, mais je n’ai jamais utilisé NUnit.Mocks - mais j’ai une certaine expérience de NMock et de Moq [que je recommande vivement, en passant]. Généralement, vous utilisez une bibliothèque moqueuse pour générer des mandataires pour les définitions d'interface, et je présume que NUnit.Mocks fonctionne de la même manière.

Par conséquent, si vous souhaitez vous moquer de votre singleton, vous devrez probablement procéder comme suit,

a. Créez une interface, disons

// 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. "Implémenter" interface

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

c. Utiliser l'interface

d'accord, donc l'étape c. est où la plupart de votre travail sera. Logiquement, si vous vous moquez de votre singleton, vous testez en fait le consommateur [que vous avez laissé de votre échantillon]. Pour c. ajoutez simplement un paramètre au ctor du consommateur, ou ajoutez une propriété accessible au public de Type 'IWebSiteConfiguration', puis en interne, référencez le membre d'instance et appelez vos méthodes contre cette nouvelle interface. Considérez ceci,

était

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)
    }
}

devient

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)
    }
}

Dans votre test unitaire, créez la maquette, transmettez une référence de la maquette au consommateur et testez le consommateur.

[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
}

Ceci sert également d’introduction pratique à l’injection de dépendance [DI]. C’est simplement une pratique consistant à transmettre ou à "injecter" des références de services [par exemple, la classe de configuration de votre site Web] au consommateur, plutôt que de demander au consommateur d’appeler le service directement [par exemple, via la classe singleton statique].

J'espère que cela vous aidera:)

Il semble y avoir une sorte de solution pour cela en utilisant la réflexion, ou peut-être que je l’ai totalement mal comprise.

Il est discuté ici: http: //www.geekbeing .com / 2010/05/23 / test-unit-singleton-hack-in-c

Pourrait-il vraiment fonctionner?

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

Projet disponible sur https://github.com/rbabreu/TestableSingleton

En fait, je ne pouvais pas le compiler sous Visual Studio car SingletonClass aurait un constructeur privé. Si quelqu'un le fait fonctionner, ce serait génial d'éviter les frais généraux liés au modèle d'adaptateur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top