在单元测试中使用DocumentDBRepository
方法模拟GetEntitiesAsync()
类后,返回null
值,而不是我希望它返回。
这是我需要测试的方法
public async Task<Books> GetBooksByBookIdAsyncByLinq(string bookId)
{
var books = await _individualRepository.GetEntitiesAsync(t => t.BookID == bookId);
if (individualResponse.Any())
{
return individualResponse.FirstOrDefault();
}
return null;
}
以下是此方法的单元测试,注意到我设置了GetEntitiesAsync()
方法并希望它返回一个账面价值。但是当我运行它时它会返回null
:
[Fact]
public void Test_GetBooksByBookIdAsyncByLinq()
{
//Arrange
var bookID = "000";
//Mock DocumentDBRepository
var mockDocumentDBRepository = new Mock<IRepository<Book>>();
var expected = Get_BookValue();
mockDocumentDBRepository.Setup(x => x.GetEntitiesAsync(x => x.BookID == bookID))
.Returns(Task.FromResult(expected));
var component = new BookComponent(mockDocumentDBRepository.Object);
//Act
var result = component.GetBooksByBookIdAsyncByLinq(bookID);
//Assert
result.Result.Should().NotBeNull().And.
BeOfType<Book>();
}
private Book Get_BookValue(){
IEnumerable<Book> result = new List<Book>
{ new Book
{ BookID = "000", BookName = "TestSourceSystemName" } };
return result;
}
当我在GetBooksByBookIdAsyncByLinq()
方法中运行单元测试和调试时,它没有从books
变量获得任何结果并返回null
而没有任何错误。
有趣的是,当我将GetEntitiesAsync()
方法更改为RunSQLQueryAsync()
方法时,这意味着使用SQL查询而不是Linq,单元测试返回正确的结果。
这是我正在测试的方法:
public async Task<Books> GetBooksByBookIdAsyncBySQL(string bookId)
{
var books = await _individualRepository.RunSQLQueryAsync("select * from c where c.BookID ==" + bookId);
if (individualResponse.Any())
{
return individualResponse.FirstOrDefault();
}
return null;
}
这是这个方法的单元测试,注意到我设置了RunQueryAsync()方法并希望返回一个book值。它的工作原理:
[Fact]
public void Test_GetBooksByBookIdAsyncBySQL()
{
//Arrange
var bookID = "000";
var sqlQuery = "select * from c where c.BookID ==" + bookId;
//Mock DocumentDBRepository
var mockDocumentDBRepository = new Mock<IRepository<Book>>();
var expected = Get_BookValue();
//mockDocumentDBRepository.Setup(x => x.GetEntitiesAsync(x => x.BookID == bookID))
// .Returns(Task.FromResult(expected));
mockDocumentDBRepository.Setup(x => x.RunQueryAsync(sqlQuery))
.Returns(Task.FromResult(expected));
var component = new BookComponent(mockDocumentDBRepository.Object);
//Act
var result = component.GetBooksByBookIdAsyncBySQL(bookID);
//Assert
result.Result.Should().NotBeNull().And.
BeOfType<Book>();
}
private Book Get_BookValue(){
IEnumerable<Book> result = new List<Book>
{ new Book
{ BookID = "000", BookName = "TestSourceSystemName" } };
return result;
}
所以我想也许我模仿GetEntitiesAsync()
方法的方式不正确。但我不确定为什么......
以下是RunQueryAsync()
和GetEntitiesAsync()
方法供参考:
public async Task<IEnumerable<T>> GetEntitiesAsync(Expression<Func<T, bool>> predicate)
{
IDocumentQuery<T> query = GetQueryByPredicate(predicate);
List<T> results = new List<T>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
public async Task<IEnumerable<T>> RunQueryAsync(string queryString)
{
IDocumentQuery<T> query = GetQueryBySQL(queryString);
List<T> results = new List<T>();
while (query.HasMoreResults)
{
results.AddRange(await query.ExecuteNextAsync<T>());
}
return results;
}
答案 0 :(得分:3)
Setup
方法尝试查看传递给方法的参数,并且仅在这些参数相同时才匹配指定的行为。
当您使用GetQueryBySQL
时,Moq能够检测到sqlQuery
字符串与传入的字符串相同(如object.Equals()
中所示),因此它可以正常工作。
当你使用GetEntitiesAsync
时,Moq会查看两个表达式并认为它们是不同的,因为表达式比较基于内存相等性。因此,即使两个x => x.BookID == bookID
看起来和你我一样,它们在运行时也是不同的表达式。
请尝试使用It.IsAny<>()
:
mockDocumentDBRepository
.Setup(x => x.GetEntitiesAsync(It.IsAny<Expression<Func<Book, bool>>()))
.Returns(Task.FromResult(expected));
假设您正常工作,可以使用Callback
或其他策略来测试传递给GetEntitiesAsync的表达式是否具有您期望它具有的行为。