如何解决模拟 Redlock.CreateAsync 不返回模拟对象
我正在尝试模拟红锁
我有下面的测试
using Moq;
using RedLockNet;
using System;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace RedLock.Tests
{
public class RedLockTests
{
[Fact]
public async Task TestMockingOfRedlock()
{
var redLockFactoryMock = new Mock<IdistributedLockFactory>();
var mock = new MockRedlock();
redLockFactoryMock.Setup(x => x.CreateLockAsync(It.IsAny<string>(),It.IsAny<TimeSpan>(),It.IsAny<CancellationToken>()))
.ReturnsAsync(mock);
var sut = new TestRedlockHandler(redLockFactoryMock.Object);
var data = new MyEventData();
await sut.Handle(data);
}
}
}
MockRedlock
是一个简单的模拟类,它实现了 IRedLock
public class MockRedlock: IRedLock
{
public void dispose()
{
}
public string Resource { get; }
public string LockId { get; }
public bool IsAcquired => true;
public RedLockStatus Status => RedLockStatus.Acquired;
public RedLockInstanceSummary InstanceSummary => new RedLockInstanceSummary();
public int ExtendCount { get; }
}
await sut.Handle(data);
是对单独事件类的调用
我已经在下面展示了这一点。这个已经简化了,但是使用下面的代码和上面的测试可以重现空引用错误
public class MyEventData
{
public string Id { get; set; }
public MyEventData()
{
Id = Guid.NewGuid().ToString();
}
}
public class TestRedlockHandler
{
private IdistributedLockFactory _redLockFactory;
public TestRedlockHandler(IdistributedLockFactory redLockFactory)
{
_redLockFactory = redLockFactory;
}
public async Task Handle(MyEventData data)
{
var lockexpiry = TimeSpan.FromMinutes(2.5);
var waitspan = TimeSpan.FromMinutes(2);
var retryspan = TimeSpan.FromSeconds(20);
using (var redlock =
await _redLockFactory.CreateLockAsync(data.Id.ToString(),lockexpiry,waitspan,retryspan,null))
{
if (!redlock.IsAcquired)
{
string errorMessage =
$"Did not acquire Lock on Lead {data.Id.ToString()}. Aborting.\n " +
$"Acquired{redlock.InstanceSummary.Acquired} \n " +
$"Error{redlock.InstanceSummary.Error} \n" +
$"Conflicted {redlock.InstanceSummary.Conflicted} \n" +
$"Status {redlock.Status}";
throw new Exception(errorMessage);
}
}
}
}
当我尝试调用它时,我希望返回我的对象,但我得到的是 null
在行上 if (!redlock.IsAcquired)
redLock
为空
缺少什么?
解决方法
CreateLockAsync
的定义
/// <summary>
/// Gets a RedLock using the factory's set of redis endpoints. You should check the IsAcquired property before performing actions.
/// Blocks and retries up to the specified time limits.
/// </summary>
/// <param name="resource">The resource string to lock on. Only one RedLock should be acquired for any given resource at once.</param>
/// <param name="expiryTime">How long the lock should be held for.
/// RedLocks will automatically extend if the process that created the RedLock is still alive and the RedLock hasn't been disposed.</param>
/// <param name="waitTime">How long to block for until a lock can be acquired.</param>
/// <param name="retryTime">How long to wait between retries when trying to acquire a lock.</param>
/// <param name="cancellationToken">CancellationToken to abort waiting for blocking lock.</param>
/// <returns>A RedLock object.</returns>
Task<IRedLock> CreateLockAsync(string resource,TimeSpan expiryTime,TimeSpan waitTime,TimeSpan retryTime,CancellationToken? cancellationToken = null);
需要一个可为空的 CancellationToken
CancellationToken? cancellationToken = null
但是模拟的设置使用
It.IsAny<CancellationToken>() //NOTE CancellationToken instead of CancellationToken?
因为设置需要不可为空的结构,但是当调用时,可以为空的 CancellationToken?
即使它为空也会被传递,
默认情况下,mock 将返回 null,因为设置与实际调用的内容不匹配。
一旦使用了正确的类型,工厂就能够返回所需的模拟
//...
redLockFactoryMock
.Setup(x => x.CreateLockAsync(It.IsAny<string>(),It.IsAny<TimeSpan>(),It.IsAny<CancellationToken?>()))
.ReturnsAsync(mock);
//...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。