2015-02-04 7 views
6

Ich arbeite daran, Verhaltensweisen im Zusammenhang mit der StackExchange.Redis-Bibliothek nachzuahmen, kann aber nicht herausfinden, wie die versiegelten Klassen, die es verwendet, korrekt dargestellt werden. Ein konkretes Beispiel ist in meinem Aufruf Code, den ich so etwas wie dies tue:Wie Moq verwenden, um die StackExchange.Redis ConnectionMultiplexer-Klasse zu mocksen?

var cachable = command as IRedisCacheable; 

    if (_cache.Multiplexer.IsConnected == false) 
    { 
     _logger.Debug("Not using the cache because the connection is not available"); 

     cacheAvailable = false; 
    } 
    else if (cachable == null) 
    { 

Der Schlüssel Linie dort ist _cache.Multiplexer.IsConnected, wo ich sicher zu machen bin Überprüfung Ich habe eine gültige Verbindung vor den Cache verwenden. Also in meinen Tests möchte ich dieses Verhalten mit so etwas verspotten:

_mockCache = new Mock<IDatabase>(); 
    _mockCache.Setup(cache => cache.Multiplexer.IsConnected).Returns(false); 

Doch während dieser Code nur gut kompiliert, bekomme ich diesen Fehler bei der Durchführung des Tests:

Moq exception thrown within the test

ich habe auch versucht, den Multiplexer Klasse spöttisch selbst, und das meinen verspottet Cache bereitstellt, aber ich laufe in der Tatsache der Multiplexer Klasse versiegelt ist:

_mockCache = new Mock<IDatabase>(); 
    var mockMultiplexer = new Mock<ConnectionMultiplexer>(); 
    mockMultiplexer.Setup(c => c.IsConnected).Returns(false); 
    _mockCache.Setup(cache => cache.Multiplexer).Returns(mockMultiplexer.Object); 

... aber das führt zu diesem Fehler:

The error thrown when trying to mock a sealed class

Letztlich mag ich kontrollieren, ob diese Eigenschaft in meinen Tests wahr oder falsch ist, so ist es eine richtige Art und Weise, so etwas zu verspotten?

Antwort

8

Der beste Ansatz meiner Meinung nach ist es, alle Ihre Redis-Interaktion in Ihrer eigenen Klasse und Schnittstelle zu wickeln. Etwas wie CacheHandler : ICacheHandler und ICacheHandler. Ihr gesamter Code würde nur mit ICacheHandler sprechen.

Auf diese Weise beseitigen Sie eine harte Abhängigkeit von Redis (Sie können die Implementierung von ICacheHandler beliebig austauschen). Sie können auch alle Interaktionen mit Ihrer Caching-Ebene verspotten, da sie auf die Schnittstelle programmiert ist.

Sie sollten StackExchange.Redis nicht direkt testen - es ist nicht Code, den Sie geschrieben haben.

+1

Ja, ich fühle mich mehr und mehr wie das ist der Ansatz, den ich nehmen müssen. Ich wollte vermeiden, die Komplexität von etwas wie ihrer * IDatabase * -Schnittstelle oder der von der ServiceStack.Redis-Bibliothek bereitgestellten Komplexität zu umhüllen, aber in Wirklichkeit brauche ich diese Funktionalität noch nicht. –

+3

Während ich dem Hinzufügen einer Wrapper-Klasse zustimme, verschiebt dieser Ansatz das Problem nicht einfach um eine Ebene zurück? Wie schreibe ich einen Komponententest für meine Wrapper-Klasse (ICacheHandler), der redis-Methoden aufruft, wenn ich sein Verhalten nicht nachahmen kann? – Necoras

+1

Tests für ICacheHandler-Implementierungen werden Integrationstests und keine Komponententests sein. – frostymarvelous

0

Verwenden Sie die Schnittstelle IConnectionMultiplexer anstelle der Betonklasse ConnectionMultiplexer in Ihrer eigenen Klasse.

public interface ICacheable 
{ 
    void DoYourJob(); 
} 

public sealed class RedisCacheHandler : ICacheable 
{ 
    private readonly IConnectionMultiplexer multiplexer; 

    public RedisCacheHandler(IConnectionMultiplexer multiplexer) 
    { 
     this.multiplexer = multiplexer; 
    } 

    public void DoYourJob() 
    { 
     var database = multiplexer.GetDatabase(1); 

     // your code   
    } 
} 

dann könnte man leicht Mock und testen:

// Arrange 
var mockMultiplexer = new Mock<IConnectionMultiplexer>(); 

mockMultiplexer.Setup(_ => _.IsConnected).Returns(false); 

var mockDatabase = new Mock<IDatabase>(); 

mockMultiplexer 
    .Setup(_ => _.GetDatabase(It.IsAny<int>(), It.IsAny<object>())) 
    .Returns(mockDatabase.Object); 

var cacheHandler = new RedisCacheHandler(mockMultiplexer.Object); 

// Act 
cacheHandler.DoYourJob(); 


// Assert 
// your tests 
Verwandte Themen