How to (should I) mock DocumentClient for DocumentDb unit testing?

后端 未结 2 1386
感动是毒
感动是毒 2020-11-30 06:48

From the new CosmosDb emulator I got sort of a repository to perform basic documentdb operations, this repository gets injected to other classes. I wanted to unit test a bas

相关标签:
2条回答
  • 2020-11-30 07:06

    The key to this is that the CreateDocumentQuery you are calling, though shown as returning IOrderedQueryable, the encapsulated result will also be derived from IDocumentQuery which is what would allow .AsDocumentQuery() to work.

    Now normally you should not be mocking what you do not own. However in this case if you want to exercise ExecuteQueryAsync to completion you can create a fake abstraction that will allow the test to be exercised to completion.

    The following Example shows how it can be done.

    [TestClass]
    public class DocumentDBRepositoryShould {
        /// <summary>
        /// Fake IOrderedQueryable IDocumentQuery for mocking purposes
        /// </summary>        
        public interface IFakeDocumentQuery<T> : IDocumentQuery<T>, IOrderedQueryable<T> {
    
        }
    
        [TestMethod]
        public async Task ExecuteQueryAsync() {
            //Arrange
            var description = "BBB";
            var expected = new List<MyDocumentClass> {
                new MyDocumentClass{ Description = description },
                new MyDocumentClass{ Description = "ZZZ" },
                new MyDocumentClass{ Description = "AAA" },
                new MyDocumentClass{ Description = "CCC" },
    
            };
            var response = new FeedResponse<MyDocumentClass>(expected);
    
            var mockDocumentQuery = new Mock<IFakeDocumentQuery<MyDocumentClass>>();
            mockDocumentQuery
                .SetupSequence(_ => _.HasMoreResults)
                .Returns(true)
                .Returns(false);
    
            mockDocumentQuery
                .Setup(_ => _.ExecuteNextAsync<MyDocumentClass>(It.IsAny<CancellationToken>()))
                .ReturnsAsync(response);
    
            var client = new Mock<IDocumentClient>();
    
            client
                .Setup(_ => _.CreateDocumentQuery<MyDocumentClass>(It.IsAny<Uri>(), It.IsAny<FeedOptions>()))
                .Returns(mockDocumentQuery.Object);
    
            var cosmosDatabase = string.Empty;
    
            var documentsRepository = new DocumentDBRepository<MyDocumentClass>(cosmosDatabase, client.Object);
    
            //Act
            var query = documentsRepository.GetQueryable(); //Simple query.
    
            var actual = await documentsRepository.ExecuteQueryAsync(query);
    
            //Assert
            actual.Should().BeEquivalentTo(expected);
        }
    }
    
    0 讨论(0)
  • 2020-11-30 07:17

    Here is Nkosi's answer ported to NSubstitute:

    [TestClass]
    public class DocumentDBRepositoryShould
    {
        [TestMethod]
        public async Task ExecuteQueryAsync()
        {
            // Arrange
            var description = "BBB";
            var expected = new List<MyDocumentClass> {
                new MyDocumentClass{ Description = description },
                new MyDocumentClass{ Description = "ZZZ" },
                new MyDocumentClass{ Description = "AAA" },
                new MyDocumentClass{ Description = "CCC" },
    
            };
            var response = new FeedResponse<MyDocumentClass>(expected);
    
            var mockDocumentQuery = Substitute.For<IFakeDocumentQuery<MyDocumentClass>>();
    
            mockDocumentQuery.HasMoreResults.Returns(true, false);
            mockDocumentQuery.ExecuteNextAsync<MyDocumentClass>(Arg.Any<CancellationToken>())
                .Returns(Task.FromResult(response));
            
            var client = Substitute.For<IDocumentClient>();
            client.CreateDocumentQuery<MyDocumentClass>(Arg.Any<Uri>(), Arg.Any<FeedOptions>())
                .ReturnsForAnyArgs(mockDocumentQuery);
            var cosmosDatabase = string.Empty;
            var documentsRepository = new DocumentDBRepository<MyDocumentClass>(cosmosDatabase, client);
            
            //Act
            var actual = await documentsRepository.GetDataAsync(); //Simple query.
    
            //Assert
            actual.Should().BeEquivalentTo(expected);
        }
    
        public class MyDocumentClass
        {
            public string Description { get; set; }
        }
        
        public interface IFakeDocumentQuery<T> : IDocumentQuery<T>, IOrderedQueryable<T> {
    
        }
        
        public class DocumentDBRepository<T>
        {
            private readonly string cosmosDatabase;
            private readonly IDocumentClient documentClient;
    
            public DocumentDBRepository(string cosmosDatabase, IDocumentClient documentClient)
            {
                this.cosmosDatabase = cosmosDatabase;
                this.documentClient = documentClient;
            }
    
            public async Task<IEnumerable<MyDocumentClass>> GetDataAsync()
            {
                var documentUri = UriFactory.CreateDocumentCollectionUri(cosmosDatabase, "test-collection");
            
                var query = documentClient
                    .CreateDocumentQuery<MyDocumentClass>(documentUri)
                    .AsDocumentQuery();
            
                var list = new List<MyDocumentClass>();
                while (query.HasMoreResults)
                {
                    var rules = await query.ExecuteNextAsync<MyDocumentClass>();
                    list.AddRange(rules);
                }
                return list;
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题