2016-09-23 2 views
0

Könnte jemand mir helfen, Mockobjects einzurichten und zu überprüfen, ob Moq Unit Testing C# verwendet wird?Problem mit Komponententest Mocking Moq

Mein Cache-Klasse ist unten angegeben:

public class InMemoryCache : ICache 
{ 
    private readonly ObjectCache _objCache = MemoryCache.Default;  

    public void Insert<T>(string cacheKey, T value) 
    { 
     _objCache.Add(cacheKey, value, DateTimeOffset.MaxValue); 
    } 
    public T Get<T>(string cacheKey) 
    { 
     if (cacheKey != null) 
      return (T)Convert.ChangeType(_objCache.Get(cacheKey), typeof(T)); 
     else 
      return default(T); 
    } 
    public bool Exists<T>(string cacheKey) 
    { 
     return _objCache.Get(cacheKey) != null; 
    } 
} 

Und mein Interface ist

public interface ICache 
{ 
    void Insert<T>(string cacheKey, T value); 
    T Get<T>(string cacheKey); 
    bool Exists<T>(string cacheKey);   
} 

ich Cachefactory bin mit meiner InMemoryCache Klasse zu nennen:

public class CacheFactory 
{ 
    public static ICache Cache { get; set; } 

    public static void Insert<T>(string cacheKey, T value) 
    { 
     Cache.Insert<T>(cacheKey, value); 
    } 

    public static T Get<T>(string cacheKey) 
    { 
     return Cache.Get<T>(cacheKey); 
    } 

    public static bool Exists<T>(string cacheKey) 
    { 
     return Cache.Get<T>(cacheKey) != null; 
    } 
} 

I Mock-Objekt versucht, wie unten und nicht in der Lage, das Ergebnis zu erhalten.

[Fact()] 
    public void CacheManager_Insert_Test() 
    { 
     string cacheKey = "GradeList"; 

     Mock<ICache> mockObject = new Mock<ICache>(); 
     List<Grade> grades = new List<Grade> 
     { 
      new Grade() {Id = 1, Name = "A*"}, 
      new Grade() {Id = 2, Name = "A"}, 
      new Grade() {Id = 3, Name = "B"}, 
      new Grade() {Id = 4, Name = "C"}, 
      new Grade() {Id = 5, Name = "D"}, 
      new Grade() {Id = 6, Name = "E"} 
     }; 

     var mockedObjectCache = new Mock<ICache>(); 
     // Setup mock's Set method 

     mockedObjectCache.Setup(m => m.Insert(cacheKey, grades)); 

     // How to get the Mocked data and verify it here 

    } 

Könnte jemand mir helfen, dass meine Daten Einsetzen Cache korrekt ist? Helfen Sie mir auch, die Cache-Daten im Komponententest Moq zu überprüfen. Ich bin neu im Komponententest und korrigiere meinen Code bei Bedarf. Ich kann das nicht überprüfen, da ich Daten in den Objektcache in meiner Implementierungsklasse einfüge, aber die Oberfläche spöttisch mache. Ich nehme an, wenn ich beides erzählen könnte, könnte es verifizieren. Nicht sicher, es ist nur meine Vermutung. Es tut mir leid, wenn das dumme Frage ist, aber Ihre Hilfe wird wirklich geschätzt.

Bitte lassen Sie mich wissen, wenn Sie weitere Details dazu benötigen.

Grüße, Viswa V.

Aktualisiert Szenario:

Betrachten wir eine andere Klasse namens "Convertor", die den Grad Namen auf der Grade-ID aus dem Cache auf Basis abruft.

public class Convertor 
{ 
    // Gets Grade ID and Displays Grade Name 
    public string GetGradeName(int gradeId) 
    { 
     var gradeList = CacheFactory.Cache.Get<List<Grade>>(CacheKeys.Grades); 
     return gradeList.Where(x => x.Id == gradeId).Select(x => x.Name).FirstOrDefault(); 
    } 
} 

Für diesen Fall, können Sie mir sagen, wie das zu überprüfen? Da diese Methode den Cache verwendet, um Werte abzurufen, bin ich mir nicht sicher, wie man hier mockt. Ihre Hilfe wird gerne in Anspruch genommen. Vielen Dank.

+0

siehe die markierte Antwort http://stackoverflow.com/questions/5864076/mocking-static-methoden –

+0

Hallo Ioana, danke für dein Update. Ich habe den Link überprüft. Es besagt, dass höhnische statische Methoden nicht möglich sind. In meiner Implementierungsklasse InMemoryCache ist es jedoch nur nicht statisch. Also, ich denke nicht, irgendwelche Probleme zu verspotten. – Viswa

Antwort

2

Sie scheinen die Verwendung von Mocks zu missverstehen. Der Grund für die Verwendung von Mocks besteht darin, abhängige Klassen zu testen, ohne sich um die Abhängigkeiten kümmern zu müssen.

Angenommen, Sie haben die folgende Klasse haben:

public class MyDependentClass { 
    private readonly ICache _cache; 
    public MyDependentClass(ICache cache) 
    { 
     _cache = cache; 
    } 

    public int CountGradesInCache() 
    { 
     // Behavior depends on what's in the _cache object 
     return _cache.Get<List<Grade>>("GradeList").Count; 
    } 
} 

Um die obige Klasse zu testen, würden Sie das ICache Objekt verspotten, die in die Klasse im Konstruktor injiziert wird. In diesem Fall wäre es sinnvoll sein, Mock zu verwenden:

string cacheKey = "GradeList"; 

    Mock<ICache> mockObject = new Mock<ICache>(); 
    List<Grade> grades = new List<Grade> 
    { 
     new Grade() {Id = 1, Name = "A*"}, 
     new Grade() {Id = 2, Name = "A"}, 
     new Grade() {Id = 3, Name = "B"}, 
     new Grade() {Id = 4, Name = "C"}, 
     new Grade() {Id = 5, Name = "D"}, 
     new Grade() {Id = 6, Name = "E"} 
    }; 

    var mockedObjectCache = new Mock<ICache>(); 
    // Setup mock's Set method 

    mockedObjectCache.Setup(m => m.Get(It.Is<string>(cacheKey))).Return(grades); 

    // Test that the dependent class acts correctly according to the grades that exist in the cache 
    var myDependentClass = new myDependentClass(mockedObjectCache.Object); 
    var gradesCount = myDependentClass.CountGradesInCache(); 

    Assert.AreEqual(6, gradesCount); 

Wir verspotten die ICache 6-Typen zurück, um den Cache-Schlüssel „GradeList“ verwendet, die die abhängige Klasse beruht auf. Wir können jetzt testen, ob die Methode MyDependentClass die Anzahl korrekt im Cache zurückgibt. Sie können auch einen Test durchführen, bei dem der Cache eine leere Liste zurückgibt, oder null, um zu überprüfen, ob das Verhalten der abhängigen Klasse in allen Fällen korrekt ist.

Es scheint in Ihrem Beispiel, Sie möchten die InMemoryCache selbst testen, in diesem Fall würden Sie nichts spotten wollen.Ich würde einfach Tests wie folgt schreiben:

var cache = new InMemoryCache(); 
var list = new List<Grade> { ... }; 
var cache.Insert("GradeList", list); 

var cachedList = cache.Get<List<Grade>>("GradeList"); 

// Assert that the list retrieved from cache has the expected values. 

Aktualisiert Szenario

Für Ihre aktualisierte Szenario können Sie den Cache nicht verspotten, wie es durch eine statische Methode auf dem CacheFactory abgerufen wird. Dies ist wahrscheinlich einer der besten Gründe, Abhängigkeitsinjektionen für Ihre Abhängigkeiten zu verwenden, anstatt sie selbst in der Klasse zu instanziieren oder statt statische Klassen/Methoden zu verwenden.

Was würde ich die Converter Klasse prüfbar machen tun, wäre ICache in die Klasse zu injizieren, statt die Verwendung CacheFactory:

public class Convertor 
{ 
    private readonly ICache _cache; 

    public Convertor(ICache cache) 
    { 
     _cache = cache; 
    } 

    public string GetGradeName(int gradeId) 
    { 
     var gradeList = _cache.Get<List<Grade>>(CacheKeys.Grades); 
     return gradeList.Where(x => x.Id == gradeId).Select(x => x.Name).FirstOrDefault(); 
    } 
} 

Jetzt würden Sie in der Lage sein, die ICache zu verspotten und testen Sie die Funktionalität von die Convertor Klasse wie ich oben beschrieben.

+0

Hallo, Danke für das Update. Noch ein Zweifel. – Viswa

+0

Könnten Sie bitte das "Aktualisierte Szenario" überprüfen und mir mitteilen, wie man die Daten überspitzt? Ich schätze deine großartige Antwort sehr. Danke im Voraus. – Viswa

+0

Danke tahatmat. Früher habe ich keine Abhängigkeitsklassen erstellt, um es zu verspotten, sondern eher die gleiche Klasse zu verspotten. Jetzt habe ich das Mocking Konzept verstanden. Danke für Ihre Erklärung. – Viswa

0

Es scheint, dass Sie in den Konzeptionen verwirrt sind.

Wenn Sie die Insert-Methode Ihrer InMemoryCache-Klasse testen (testen) möchten, sollten Sie den InMemoryCache nicht überspionieren.

Mocking ist für die 3rd-Party-Klassen, die in der Klasse verwendet werden, die Sie testen möchten.

In der Tat haben Sie auch eine Abhängigkeit in Ihrer Einsatzmethode:

private readonly ObjectCache _objCache = MemoryCache.Default; 

Also, sollten Sie die Object Instanz irgendwie verspotten.

Aber diesmal Objectcache muss aus verwandten Schnittstelle, um geerbt in Moq lib verwendet werden, dh IObjectCache

Und Sie sollten verwenden:

var mockObjectCache = new Mock<IObjectCache>(); 
... 

//Verifying: 
mockObjectCache.Verify(cache => cache.Add(It.IsAny<string>())).Should().Be(true); 

Allerdings ist Objectcache-Klasse von IEnumerable und IEnumerable geerbt> , so können Sie es nicht direkt verspotten. Sie sollten eine Bridge-Schnittstelle (Anti-Korruptions-Ebene) verwenden, wenn Sie wirklich mocken müssen.

+1

Schöne Erklärung! Danke für das Update! – Viswa

+1

Danke Skynyrd! Ich akzeptiere auch diese Lösung, da es für mich hilfreich ist, den Fehler, den ich gemacht habe, zu verstehen. Ich versuche, die InMemoryCache-Objekte zu verspotten, ohne die Abhängigkeit von ObjectCache zu überprüfen. Ich verstehe auch, dass es nicht die richtige Art ist, die InMemoryCache-Klasse zu verspotten. – Viswa

+0

Ich freue mich, dass Sie Viswa besser verstehen, viel Glück! – skynyrd

Verwandte Themen