I'm writing unit test. For testing the method below,
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;
}
I mocked dbset and 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);
}
everything works as expect except the AddAsync
, the exception is
Invalid callback. Setup on method with parameters (WebJobStatus,CancellationToken) cannot invoke callback with parameters (WebJobStatus).
Anyone has any idea?
You will need to return a Task to allow the async/await call
await _dbContext.WebJobStatus.AddAsync(newWebJobStatus);
to flow to completion.
So assuming that Add returns the object added
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));
Note that the method being Setup
takes two arguments, so the Callback
and Returns
will need to expect two arguments as well if they want to use the captured arguments.
In .net core 3.1, I had to rewrite the Returns
as below:
.Returns((T model, CancellationToken token) => new ValueTask<EntityEntry<T>>());
Not pretty, but this was the only way I found to mock AddAsync and make it return an actual value:
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)
)));
The way I have done mocking is the following:-
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();
And the actual implementation is the following:-
public async Task<int> AddMyClassAsync(MyClass myClass)
{
await _careMapsDataContext.MyClasses.AddAsync(myClass);
return await _careMapsDataContext.SaveChangesAsync();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With