我正在努力模拟与StackExchange.Redis库相关的行为,但无法弄清楚如何正确模拟它使用的密封类。一个具体的例子是在我的调用代码中我做了这样的事情:
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)
{
其中的关键行是 _cache.Multiplexer.IsConnected ,我在检查之前确保在使用缓存之前有一个有效的连接。所以在我的测试中,我想用这样的东西来模拟这种行为:
_mockCache = new Mock<IDatabase>();
_mockCache.Setup(cache => cache.Multiplexer.IsConnected).Returns(false);
但是,虽然该代码编译得很好,但在运行测试时出现此错误:
我也试过模拟多路复用器类本身,并将其提供给我的模拟缓存,但我遇到了多路复用器类被密封的事实:
_mockCache = new Mock<IDatabase>();
var mockMultiplexer = new Mock<ConnectionMultiplexer>();
mockMultiplexer.Setup(c => c.IsConnected).Returns(false);
_mockCache.Setup(cache => cache.Multiplexer).Returns(mockMultiplexer.Object);
...但这会导致此错误:
最终我想在我的测试中控制该属性是真还是假,所以有没有正确的方法来模拟这样的东西?
答案 0 :(得分:10)
我认为最好的方法是将所有Redis交互包装在您自己的类和接口中。像CacheHandler : ICacheHandler
和ICacheHandler
之类的东西。您的所有代码都只会与ICacheHandler
对话。
这样,您就消除了对Redis的强烈依赖(您可以根据需要更换ICacheHandler
的实现)。您还可以模拟与缓存层的所有交互,因为它是针对接口编程的。
您不应该直接测试StackExchange.Redis
- 这不是您编写的代码。
答案 1 :(得分:5)
在您自己的班级中使用界面IConnectionMultiplexer而不是具体的班级ConnectionMultiplexer。
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
}
}
然后你可以轻松地模拟和测试它:
// 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
答案 2 :(得分:0)
上面的答案中未包括的更详细的嘲笑数据库实例设置。我很难找到一个可行的示例来模拟IDatabase StringGet方法(例如,处理可选参数,使用RedisKey与字符串,使用RedisValue与字符串等)之类的简单操作,所以我想与我分享一下。这是对我有用的。
此测试设置:
var expected = "blah";
RedisValue expectedValue = expected;
mockDatabase.Setup(db => db.StringGet(It.IsAny<RedisKey>(), It.IsAny<CommandFlags>()))
.Returns(expectedValue);
要影响此经过测试的方法调用返回的内容:
var redisValue = _connectionMultiplexer.GetDatabase().StringGet(key);