Unit Testing and Mocking MongoDB Extension Method in .NET Core – Part2

In Part 2 of the article, I shall talk about how to Unit Test and Mock MongoDB method .NET Core.

Today in this article, we will cover below aspects,

We shall use the Synchronous method using the extension method FindSync() to validate IAsyncCursor results.

We already looked at a Unit testing solution for an approach with filter criteria in the below article,





As discussed, Technically IAsyncCursor is equivalent to IEnumerable which provides the capability of iterating over the collection asynchronously.



A few extension methods are as below,



  • FindSync
  • FindAsync
  • InsertOneAsync



In this post, we shall write the unit test for the method that uses the FindSync method.



We shall be using the same naming conventions for unit testing that we learned in our last article,





Unit Test MongoDB Synchronous methods

As we are dealing with the target Synchronous method hence we will write a unit test and mock of synchronous extension methods.

Unit test and Mock IAsyncCursor

Let’s now mock IAsyncursor. Overall there are two methods that IAsyncursor exposes. We shall mock them easily.

The IAsyncCursor<TDocument> type exposes the following methods,

  • MoveNext()
  • MoveNextAsync()

As we are dealing with the Synchronous method we will mock MoveNext() method as below

            //Mock MoveNext
             
             Mock<IAsyncCursor<Book>> _bookCursor = new Mock<IAsyncCursor<Book>>();
            _bookCursor.Setup(_ => _.Current).Returns(_list); 
            _bookCursor
                .SetupSequence(_ => _.MoveNext(It.IsAny<CancellationToken>()))
                .Returns(true)
                .Returns(false);


The complete test method is as below,

        
        [Fact]
        public  void BookRepository_GetBookSync_Valid_Success()
        {
            //Arrange

            //Mock MoveNext

            Mock<IAsyncCursor<Book>> _bookCursor = new Mock<IAsyncCursor<Book>>();
            _bookCursor.Setup(_ => _.Current).Returns(_list);
            _bookCursor
                .SetupSequence(_ => _.MoveNext(It.IsAny<CancellationToken>()))
                .Returns(true)
                .Returns(false);

            //Mock FindSync

            _mockCollection.Setup(op => op.FindSync(It.IsAny<FilterDefinition<Book>>(),
            It.IsAny<FindOptions<Book, Book>>(),
            It.IsAny<CancellationToken>())).Returns(_bookCursor.Object);

            //Mock GetCollection

            _mockContext.Setup(c => c.GetCollection<Book>(typeof(Book).Name)).Returns(_mockCollection.Object);

            var bookRepo = new BookRepository(_mockContext.Object);

            //Act
            var result =  bookRepo.GetAllSync();

            //Assert 
            //Lets loop only first item and assert
            foreach (Book book in result)
            {
                Assert.NotNull(book);
                Assert.Equal(book.Name, _book.Name);
                Assert.Equal(book.Author, _book.Author);
                break;
            }

            //Verify if InsertOneAsync is called once 

            _mockCollection.Verify(c => c.FindSync(It.IsAny<FilterDefinition<Book>>(),
                It.IsAny<FindOptions<Book>>(),
                 It.IsAny<CancellationToken>()), Times.Once);
        }

Below is how I can set up the unit test with mockup data,

Unit Test and Mock MongoDB extension method NET Core

Sometimes framework-dependent extension methods are really difficult to test.

In such scenarios, we should only test for its execution once or twice, etc. rather than actual results.

We can very much make use of the Assertion method like ‘Verify‘ to validate the same.

Unit Test MongoDB Asynchronous method

Please visit the below article for the Asynchronous method,

Other References :

Do you have any better suggestions to test the method with AsyncCursor?

Please sound off your comments below!



Please bookmark this page and share it with your friends. Please Subscribe to the blog to receive notifications on freshly published(2024) best practices and guidelines for software design and development.



5 thoughts on “Unit Test and Mock MongoDB extension method .NET- Part2

  1. Whenever I try insertone on the mocked IMongoCollection, it does not actually insert.
    For example (data is the object and setup correctly):

    var result = _mockCollection.Object.InsertOneAsync(data, new InsertOneOptions() {
    BypassDocumentValidation = true }, new CancellationToken());
    await result;
    _mockCollection.Object.InsertOne(data)
    long count = _mockCollection.Object.EstimatedDocumentCount();
    When these lines run, before any of the mocking, (this is purely just setting up the collection to be used) the collection will have a count of 0. Then later on the mocking, the findasync brings back my list of one object but it’s from the list of the generic collection we made and added to. As soon as the firstordefault function comes around the list is empty because the collection is empty and so it returns null and my test fails.
    How were you able to insert that document?

    1. Hi Jon- Thanks for your query. In the above example, the important step is to define the _list object which is defined as a generic list of type Book(Please check the screenshot where the BooksRepositoryTests constructor is initialized). This we later use in the return statement while mocking.
      Hope this resolves the issue.

      1. I did have a _list object instantiated and this is passed through as the current collection for the iasynccursor however the actual _mockCollection is what is not being populated. as you can see your example you populate two lists. The mocked collection and the generic collection. Both need to be populated. When I call countdocuments on the mocked collection it returns 0 instead of 1 after the “insertone” function..It looks like yours is actually populating.

  2. Hello,
    Great Post but it is not working for me!
    I am able to mock the most of the things but I am not able to mock my Context which is giving me “Unsupported expression Non-Overridable members” error.
    Could you please share snapshot of what you written in IMongoBookDBContext.cs file.

    It will help me in refactoring the code and get the mock done.

  3. Hello! Great post! It saved my life!
    I have a question.
    I have a method that calls two times to FindSync from the same collection. The second call always returns a list with zero elements. No matter what I do. I’ve tried to set up two lists in the cursor and two cursors in the collection with SetupSequence, but no luck.
    How can I solve this problem?

    thanks a lot!

Leave a Reply

Your email address will not be published. Required fields are marked *