【问题标题】:How can I mock the Azure Redis Cache?如何模拟 Azure Redis 缓存?
【发布时间】:2016-08-03 13:17:34
【问题描述】:

如何模拟 Azure Redis 缓存?

我想为我的一个使用 Azure Redis 缓存的应用程序编写单元测试。由于我在编写单元测试代码时对模拟和存根完全陌生,因此我正在寻求有关如何从模拟/存根缓存组件的基本脚本开始的帮助。

【问题讨论】:

    标签: c# rhino-mocks justmock


    【解决方案1】:

    使用数据库、文件和缓存等外部资源进行测试是集成测试,非单元。您可以在单元测试中测试的事实是,您的代码正在调用缓存方法。

    所以,首先,你需要一个缓存服务的接口。这个接口不仅可以让你测试你的代码,还可以让你使用不同的缓存服务器。

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

    【讨论】:

    • 感谢您的帮助!但是,第三步是在 - void Add(string key, TimeSpan life, T value) { LifeTimeValue =lifetime; AddValue = 价值; } 由于值的类型是 T。
    • 如果你能给出一个简单的 set 示例并从 Redis 缓存中获取对象以及随后的测试代码,那就太好了。谢谢!
    • 我更正了方法AddTryGet的实现中的错误。关于您的第二条评论:我的回答描述了缓存逻辑的单元测试。如果你想在测试中调用 Redis 方法,会有集成测试,而不是单元。
    • 感谢您的建议/回复。
    猜你喜欢
    • 2015-04-16
    • 1970-01-01
    • 2018-04-25
    • 2016-09-10
    • 2019-05-17
    • 1970-01-01
    • 2016-06-04
    • 2021-05-09
    • 1970-01-01
    相关资源
    最近更新 更多