使用GetEntitiesAync(DocumentDB)的方法的单元测试

时间:2018-05-25 22:37:46

标签: linq unit-testing asp.net-core moq azure-cosmosdb

在单元测试中使用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;
        }

1 个答案:

答案 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的表达式是否具有您期望它具有的行为。