c#MongoDb

How to mock the MongoDb GetCollection

In real-time scenarios, we would not call the actual Database to hit the logic for writing the unit test cases. Instead, we will mock to isolate the database code. Mock the MongoDb GetCollection method is a little easier than we think. The mock framework we will use in the sample is MOQ, and it is relatively easy to implement. We will see the simple example.

Create a sample document in the employee collection.

{
     "_id" : ObjectId("60562f172852791588534415"),
     "FirstName" : "Ravinder",
     "LastName" : "Singh",
     "Address" : {
         "street" : "xyz",
         "place" : "xyz"
     }
 } 

Create the data models for the Employee Collection.

 public class Employee
     {
         [BsonId]
         [BsonRepresentation(BsonType.ObjectId)]
         public string  Id { get; set; }
  
         public string FirstName { get; set; }
  
         public string LastName { get; set; }
  
         public Address Address { get; set; }
     }
  
 public class Address
     {
         public string street { get; set; }
         public string place { get; set; }
     } 

Create the MongoDbprovider Helper class for the Database operations.

 public interface IMongoDBProvider
     {
         IMongoCollection<T> GetCollection<T>(string collectionName);
     }

 public class MongoDbProvider : IMongoDBProvider
     {
         private IMongoClient client;
         private IMongoDatabase database;
  
         public MongoDbProvider()
         {
             this.client = new MongoClient();
             MongoUrl url = new MongoUrl("mongodb://localhost:27017/SampleDB");
             MongoClientSettings settings = MongoClientSettings.FromUrl(url);
             this.client = new MongoClient(settings);
             this.database = this.client.GetDatabase(url.DatabaseName);
         }
  
         public IMongoCollection<T> GetCollection<T>(string collectionName)
         {
             return this.database.GetCollection<T>(collectionName);
         }
     } 

Create the sample console app to fetch the employee records from the MongoDB collection.

 public class Program
     {
         private readonly IMongoDBProvider dbProvider;
  
         public Program(IMongoDBProvider dbProvider)
         {
             this.dbProvider = dbProvider;
         }
  
         public List<Employee> GetAllEmployee()
         {
             return dbProvider.GetCollection<Employee>("Employee").Aggregate<Employee>(this.MatchStage()).ToList();
         }
  
         private BsonDocument[] MatchStage()
         {
             return new BsonDocument[]
             {
                 new BsonDocument(
                 "$match",
                      new BsonDocument
                          {
  
                             { "FirstName", "Ravinder" }
                         })
             };
         }
  
         private static void Main(string[] args)
         {
             IMongoDBProvider provider = new MongoDbProvider();
             Program pgm = new Program(provider);
             List<Employee> result = pgm.GetAllEmployee();
         }
     } 

Following is the core function definition to call the Aggregate.

IAsyncCursor<TResult> Aggregate<TResult>(PipelineDefinition<TDocument, TResult> pipeline, AggregateOptions options = null, CancellationToken cancellationToken = default);

So we have to prepare the mock objects for IAsyncCursor, Aggregate, GetCollection.

Create a unit test project to mock the GetCollection method.

  [TestClass]
     public class UnitTest1
     {
        [TestMethod]
         public void Program_GetEmployee_Return_Records_Sucessfully()
         {
             List<Employee> fakeRecords = new List<Employee>()
             {
                 new Employee
                 {
                     FirstName = "Harbhajan",
                     LastName = "Singh",
                     Address = new Address
                     {
                         place ="abc",
                         street ="abc"
                     }
  
                 }
             };
  
             var mockMongoCollection = new Mock<IMongoCollection<Employee>>();
  
             //Mock IAsyncCursor
             var mockCursor = new Mock<IAsyncCursor<Employee>>();
             mockCursor.Setup(x => x.Current).Returns(fakeRecords);
             mockCursor.SetupSequence(x => x.MoveNext(It.IsAny<CancellationToken>())).Returns(true);
  
             //Mock Aggregate
             mockMongoCollection.Setup(x => x.Aggregate<Employee>(It.IsAny<PipelineDefinition<Employee, Employee>>(), null,  It.IsAny<CancellationToken>()))
                                .Returns(mockCursor.Object);
  
             //Mock GetCollection
  
             Mock<IMongoDBProvider> mockDbprovider = new Mock<IMongoDBProvider>();
             mockDbprovider.Setup(x => x.GetCollection<Employee>("Employee")).Returns(mockMongoCollection.Object);
  
             Program pgm = new Program(mockDbprovider.Object);
             var result = pgm.GetAllEmployee();
  
             Assert.IsNotNull(result);
             Assert.AreEqual(result[0].FirstName, "Harbhajan");
             Assert.AreEqual(result[0].LastName, "Singh");
         }
     } 

We have created the required mock objects in the above code to isolate the Db functionality using MOQ and thus reduce the pain of isolating the database dependencies during unit testing.

Happy coding!….