How to use Moq for the layout of the StackExchange.Redis ConnectionMultiplexer class?

I am working on creating behavior related to the StackExchange.Redis library, but I cannot figure out how to properly mock the private classes that it uses. A specific example in my code: I am doing something like this:

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

The key line has _cache.Multiplexer.IsConnected, where I check to make sure that I have a valid connection before using the cache. So in my tests, I want this behavior to be related to something like this:

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

However, although this code compiles just fine, I get this error when running the test:

Moq exception thrown within the test

I also tried to make fun of the multiplexer class itself and provided this for my mocking cache, but I came across the fact that the multiplexer class is sealed:

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

... but this leads to an error:

The error thrown when trying to mock a sealed class

Ultimately, I want to control whether this property is true or false in my tests, so is there a proper way to do something like this?

+6
source share
2 answers

The best approach, in my opinion, is to combine all your interactions with Redis in your own class and interface. Something like CacheHandler : ICacheHandler and ICacheHandler . All your code will only talk with ICacheHandler .

Thus, you eliminate the strong dependence on Redis (you can change the implementation of ICacheHandler at your discretion). You can also mock all interactions with your cache level because it is programmed into the interface.

You should not test StackExchange.Redis directly - this is not the code you wrote.

+8
source

Use the IConnectionMultiplexer interface instead of the concrete ConnectionMultiplexer class in your own class.

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

Then you could easily make fun and test it:

 // 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 
0
source

Source: https://habr.com/ru/post/981991/


All Articles