【发布时间】:2016-08-03 13:17:34
【问题描述】:
如何模拟 Azure Redis 缓存?
我想为我的一个使用 Azure Redis 缓存的应用程序编写单元测试。由于我在编写单元测试代码时对模拟和存根完全陌生,因此我正在寻求有关如何从模拟/存根缓存组件的基本脚本开始的帮助。
【问题讨论】:
标签: c# rhino-mocks justmock
如何模拟 Azure Redis 缓存?
我想为我的一个使用 Azure Redis 缓存的应用程序编写单元测试。由于我在编写单元测试代码时对模拟和存根完全陌生,因此我正在寻求有关如何从模拟/存根缓存组件的基本脚本开始的帮助。
【问题讨论】:
标签: c# rhino-mocks justmock
使用数据库、文件和缓存等外部资源进行测试是集成测试,非单元。您可以在单元测试中测试的事实是,您的代码正在调用缓存方法。
所以,首先,你需要一个缓存服务的接口。这个接口不仅可以让你测试你的代码,还可以让你使用不同的缓存服务器。
public interface ICache
{
void Add<T>(string key, TimeSpan lifetime, T value);
bool TryGet<T>(string key, out T value);
void Remove(string key);
. . .
}
其次,你需要域代码来测试:
public class SleepingMembersService
{
private readonly TimeStamp _lifetime = TimeStamp.FromMinutes(5);
private readonly ICache _cache;
private readonly INotifier _notifier;
public SleepingMembersService(ICache cache, INotifier notifier)
{
_cache = cache;
_notifier = notifier;
}
private string MakeKey(User user) => $"unsleepingUser{user.Id}";
public void WakeUpIfSleep(IUser user)
{
var key = MakeKey(user);
bool isWaking;
if (_cache.TryGet(key, out isWaking) && isWaking)
return;
notifier.Notify(user.Id, "Wake up!");
}
public void ConfirmImNotSleeping(IUser user)
{
var key = MakeKey(user);
_cache.Add(key, _lifeTime, true);
}
}
第三,让我们做存根缓存:
public class StubCache : ICache
{
public bool TryGetResult { get; set; }
public bool TryGetValue { get; set; }
public bool AddValue { get; set; }
public TimeStamp LifeTimeValue { get; set; }
void Add<T>(string key, TimeSpan lifetime, T value)
{
LifeTimeValue = lifetime;
AddValue = (bool)(object)value;
}
bool TryGet<T>(string key, out T value)
{
value = (T)(object)TryGetValue;
return TryGetResult;
}
. . .
}
最后你可以编写单元测试了:
pubic void ConfirmImNotSleeping_WhenCalled_CallsAdd()
{
var cache = new StubCache<bool>();
var notifier = new StubNotifier();
var service = new SleepingMembersService(cache, notifier);
var user = new StubUser(1, "John Doe");
service.ConfirmNotSleeping(user);
Assert.IsTrue(cache.AddValue);
}
好吧,您已经检查了方法ConfirmNotSleeping 调用了方法Add。
现在,您应该为 Redis 实现 ICache:
public RedisCache : ICache
{
private IConnectionMultiplexer connection;
public bool TryGet<T>(string key, out T value)
{
var cache = Connection.GetDatabase();
var rValue = cache.StringGet(key);
if (!rValue.HasValue)
{
value = default(T);
return false;
}
value = JsonConvert.DeserializeObject<T>(rValue);
return true;
}
. . .
}
为了简化实现存根和模拟,您可以使用 Moq 之类的库。这些库让您可以根据您的目的自动生成存根和模拟。所以你的测试代码会是这样的:
pubic void ConfirmImNotSleeping_WhenCalled_CallsAdd()
{
var cacheStub = new Mock<ICache>();
var notifierStub = new Mock<INotifier>();
var service = new SleepingMembersService(cache.Object, notifier.Object);
var userStub = new Mock<IUser>();
service.ConfirmNotSleeping(user.Object);
cacheStub.Vertify(x => x.Add(It.IsAny<string>(), It.IsAny<TimeStamp>(), true));
}
【讨论】:
Add和TryGet的实现中的错误。关于您的第二条评论:我的回答描述了缓存逻辑的单元测试。如果你想在测试中调用 Redis 方法,会有集成测试,而不是单元。