我如何模拟 AddAsync?
How do I mock AddAsync?
我正在编写单元测试。为了测试下面的方法,
public async Task<Guid> CreateWebJobStatus(string blobId, Guid loggedInUserId, string loggedInUserEmail) {
Guid webJobStatusId = Guid.NewGuid();
WebJobStatus newWebJobStatus = new WebJobStatus
{
WorkJobStatusId = webJobStatusId,
TransactionId = Guid.NewGuid(),
Status = (int)WebJobStatusEnum.PENDING,
BlobId = blobId,
UserId = loggedInUserId,
UserEmail = loggedInUserEmail,
};
await _dbContext.WebJobStatus.AddAsync(newWebJobStatus);
await _dbContext.SaveChangesAsync();
return webJobStatusId;
}
我模拟了 dbset 和 dbcontext
public async void CreateWebJobStatusTest() {
var dbOption = new DbContextOptions<TimeSeriesDbContext>();
var mockDbContext = new Mock<TimeSeriesDbContext>(dbOption);
var mockConfig = new Mock<IConfiguration>();
var instance = new WebJobStatusRepository(mockConfig.Object, mockDbContext.Object);
var mockValidWebJobId = "11111111-1111-1111-1111-111111111111";
var webjobStatusList = new List<WebJobStatus>() {
new WebJobStatus {
WorkJobStatusId = Guid.Parse(mockValidWebJobId),
GroupName = "testGroupName",
Status = 3,
CreatedDate = DateTimeOffset.UtcNow.AddDays(-10)
}
};
var mockWebJobDbSet = UnitTestUtil.CreateDbSetMock<WebJobStatus>(webjobStatusList.AsQueryable());
mockDbContext.Setup(x => x.WebJobStatus).Returns(mockWebJobDbSet.Object);
mockWebJobDbSet.Setup(x => x.AddAsync(It.IsAny<WebJobStatus>(), It.IsAny<System.Threading.CancellationToken>())).Callback((WebJobStatus wj) =>{webjobstatusList.add(wj);});
var mockuserId = Guid.Parse("22222222-1111-1111-1111-111111111111");
var result = await instance.CreateWebJobStatus("testBlobId.tsv", mockuserId, "testEmail");
Assert.IsType<Guid>(result);
mockDbContext.Verify(x => x.SaveChangesAsync(It.IsAny<System.Threading.CancellationToken>()), Times.Once);
mockWebJobDbSet.Verify(x => x.AddAsync(It.IsAny<WebJobStatus>(), It.IsAny<System.Threading.CancellationToken>()), Times.Once);
}
除 AddAsync
外,一切正常,例外是
Invalid callback. Setup on method with parameters (WebJobStatus,CancellationToken) cannot invoke callback with parameters (WebJobStatus).
有人知道吗?
您将需要 return 一个任务以允许 async/await 调用
await _dbContext.WebJobStatus.AddAsync(newWebJobStatus);
流向完成。
所以假设 Add returns 添加了对象
mockWebJobDbSet
.Setup(_ => _.AddAsync(It.IsAny<WebJobStatus>(), It.IsAny<System.Threading.CancellationToken>()))
.Callback((WebJobStatus model, CancellationToken token) => { webjobstatusList.Add(model); })
.Returns((WebJobStatus model, CancellationToken token) => Task.FromResult((EntityEntry<WebJobStatus>)null));
请注意,Setup
方法有两个参数,因此 Callback
和 Returns
如果要使用捕获的参数,也需要有两个参数。
在 .net core 3.1 中,我不得不重写 Returns
如下:
.Returns((T model, CancellationToken token) => new ValueTask<EntityEntry<T>>());
不漂亮,但这是我发现模拟 AddAsync 并使其 return 成为实际值的唯一方法:
mockWebJobDbSet
.Setup(_ => _.AddAsync(It.IsAny<WebJobStatus>(), It.IsAny<CancellationToken>()))
.Callback((WebJobStatus model, CancellationToken token) => { webjobStatusList.Add(model); })
.Returns((WebJobStatus model, CancellationToken token) => ValueTask.FromResult(new EntityEntry<WebJobStatus>
(new InternalEntityEntry(
new Mock<IStateManager>().Object,
new RuntimeEntityType("WebJobStatus", typeof(WebJobStatus), false, null, null, null, ChangeTrackingStrategy.Snapshot, null, false),
model)
)));
我模拟的方式如下:-
var myList = new List<MyClass>();
_dataContext.Setup(m => m.MyClasses.AddAsync(It.IsAny<MyClass>(), default))
.Callback<Slide, CancellationToken>((s, token) => {myList.Add(s);});
_dataContext.Setup(c => c.SaveChangesAsync(default))
.Returns(Task.FromResult(1))
.Verifiable();
实际执行情况如下:-
public async Task<int> AddMyClassAsync(MyClass myClass)
{
await _careMapsDataContext.MyClasses.AddAsync(myClass);
return await _careMapsDataContext.SaveChangesAsync();
}
我正在编写单元测试。为了测试下面的方法,
public async Task<Guid> CreateWebJobStatus(string blobId, Guid loggedInUserId, string loggedInUserEmail) {
Guid webJobStatusId = Guid.NewGuid();
WebJobStatus newWebJobStatus = new WebJobStatus
{
WorkJobStatusId = webJobStatusId,
TransactionId = Guid.NewGuid(),
Status = (int)WebJobStatusEnum.PENDING,
BlobId = blobId,
UserId = loggedInUserId,
UserEmail = loggedInUserEmail,
};
await _dbContext.WebJobStatus.AddAsync(newWebJobStatus);
await _dbContext.SaveChangesAsync();
return webJobStatusId;
}
我模拟了 dbset 和 dbcontext
public async void CreateWebJobStatusTest() {
var dbOption = new DbContextOptions<TimeSeriesDbContext>();
var mockDbContext = new Mock<TimeSeriesDbContext>(dbOption);
var mockConfig = new Mock<IConfiguration>();
var instance = new WebJobStatusRepository(mockConfig.Object, mockDbContext.Object);
var mockValidWebJobId = "11111111-1111-1111-1111-111111111111";
var webjobStatusList = new List<WebJobStatus>() {
new WebJobStatus {
WorkJobStatusId = Guid.Parse(mockValidWebJobId),
GroupName = "testGroupName",
Status = 3,
CreatedDate = DateTimeOffset.UtcNow.AddDays(-10)
}
};
var mockWebJobDbSet = UnitTestUtil.CreateDbSetMock<WebJobStatus>(webjobStatusList.AsQueryable());
mockDbContext.Setup(x => x.WebJobStatus).Returns(mockWebJobDbSet.Object);
mockWebJobDbSet.Setup(x => x.AddAsync(It.IsAny<WebJobStatus>(), It.IsAny<System.Threading.CancellationToken>())).Callback((WebJobStatus wj) =>{webjobstatusList.add(wj);});
var mockuserId = Guid.Parse("22222222-1111-1111-1111-111111111111");
var result = await instance.CreateWebJobStatus("testBlobId.tsv", mockuserId, "testEmail");
Assert.IsType<Guid>(result);
mockDbContext.Verify(x => x.SaveChangesAsync(It.IsAny<System.Threading.CancellationToken>()), Times.Once);
mockWebJobDbSet.Verify(x => x.AddAsync(It.IsAny<WebJobStatus>(), It.IsAny<System.Threading.CancellationToken>()), Times.Once);
}
除 AddAsync
外,一切正常,例外是
Invalid callback. Setup on method with parameters (WebJobStatus,CancellationToken) cannot invoke callback with parameters (WebJobStatus).
有人知道吗?
您将需要 return 一个任务以允许 async/await 调用
await _dbContext.WebJobStatus.AddAsync(newWebJobStatus);
流向完成。
所以假设 Add returns 添加了对象
mockWebJobDbSet
.Setup(_ => _.AddAsync(It.IsAny<WebJobStatus>(), It.IsAny<System.Threading.CancellationToken>()))
.Callback((WebJobStatus model, CancellationToken token) => { webjobstatusList.Add(model); })
.Returns((WebJobStatus model, CancellationToken token) => Task.FromResult((EntityEntry<WebJobStatus>)null));
请注意,Setup
方法有两个参数,因此 Callback
和 Returns
如果要使用捕获的参数,也需要有两个参数。
在 .net core 3.1 中,我不得不重写 Returns
如下:
.Returns((T model, CancellationToken token) => new ValueTask<EntityEntry<T>>());
不漂亮,但这是我发现模拟 AddAsync 并使其 return 成为实际值的唯一方法:
mockWebJobDbSet
.Setup(_ => _.AddAsync(It.IsAny<WebJobStatus>(), It.IsAny<CancellationToken>()))
.Callback((WebJobStatus model, CancellationToken token) => { webjobStatusList.Add(model); })
.Returns((WebJobStatus model, CancellationToken token) => ValueTask.FromResult(new EntityEntry<WebJobStatus>
(new InternalEntityEntry(
new Mock<IStateManager>().Object,
new RuntimeEntityType("WebJobStatus", typeof(WebJobStatus), false, null, null, null, ChangeTrackingStrategy.Snapshot, null, false),
model)
)));
我模拟的方式如下:-
var myList = new List<MyClass>();
_dataContext.Setup(m => m.MyClasses.AddAsync(It.IsAny<MyClass>(), default))
.Callback<Slide, CancellationToken>((s, token) => {myList.Add(s);});
_dataContext.Setup(c => c.SaveChangesAsync(default))
.Returns(Task.FromResult(1))
.Verifiable();
实际执行情况如下:-
public async Task<int> AddMyClassAsync(MyClass myClass)
{
await _careMapsDataContext.MyClasses.AddAsync(myClass);
return await _careMapsDataContext.SaveChangesAsync();
}