skip to Main Content

I am trying to write down unit test for my repository which is interacting with MongoDb but facing a problem/exception in mocking the objects. This is what I have tried so far;

This is how my class looks like i.e. I have create a repository class and extend it from interface;

public class UserManagementRepository : IUserManagementRepository
{
    private readonly IMongoCollection<UserModel> _users;
    public UserManagementRepository(IDatabaseSettings dbSettings, IApplicationSettings applicationSettings, IMongoClient mongoClient)
    {
        IMongoDatabase database = mongoClient.GetDatabase(dbSettings.DatabaseName);
        _users = database.GetCollection<UserModel>(applicationSettings.UserCollectionName);
    }
    
    public async Task<GeneralResponse> Get(string id)
    {
        GeneralResponse response = new GeneralResponse();
        try
        {
            IAsyncCursor<UserModel> userModel = await _users.FindAsync(user => user.Id == id);
            if (userModel != null)
            {
                response.Message = "User exists!";
                response.Data = userModel.FirstOrDefault();
                response.ResponseCode = ResponseCode.Success;
            }
            else
            {
                response.Message = $"User with Id: {id} not found!";
                response.ResponseCode = ResponseCode.Success;
            }
        }
        catch (Exception ex)
        {
            response.Message = "Failure";
            response.ResponseCode = ResponseCode.Error;
        }
        return response;
    }
}

This is how my Test class look like

public class UserManagmentRepositoryTests
{
    private Mock<IDatabaseSettings> _mockDbSettings;
    private Mock<IApplicationSettings> _mockApplicationSettings;
    private Mock<IMongoClient> _mockClient;
    public UserManagmentRepositoryTests()
    {
        _mockDbSettings = new Mock<IDatabaseSettings>();
        _mockApplicationSettings = new Mock<IApplicationSettings>();
        _mockClient = new Mock<IMongoClient>();
    }

    [Fact]
    public async Task GetUserWithId_Test()
    {
        // Arrange
        var repo = new Mock<IUserManagementRepository>();
        IDatabaseSettings dbSettings = new DatabaseSettings()
        {
            ConnectionString = "mongodb:connectionstring",
            DatabaseName = "dbname"
        };
        _mockDbSettings.Setup(x => x).Returns(dbSettings);

        IApplicationSettings applicationSettings = new ApplicationSettings() { UserCollectionName = "users" };
        _mockApplicationSettings.Setup(app => applicationSettings).Returns(applicationSettings);

        MongoClientSettings clientSettings = MongoClientSettings.FromConnectionString(dbSettings.ConnectionString);
        MongoClient client = new MongoClient(clientSettings);
        _mockClient.Setup(c => client);

        var ctr = new UserManagementRepository(_mockDbSettings.Object, _mockApplicationSettings.Object, _mockClient.Object);

        // Act
        var result = ctr.Get("132");

        // Assert
        //result.StatusCode.Should().NotBeNull();
    }
}

I get an exception on every setup

Exception

3

Answers


  1. To use your ApplicationSettings as mocked ApplicationSettings, you must use an expression in the setup method.

    Instead of:

        IApplicationSettings applicationSettings = new ApplicationSettings() { UserCollectionName = "users" };
        _mockApplicationSettings.Setup(app => applicationSettings).Returns(applicationSettings);
    
    

    Use e.g. this:

        IApplicationSettings applicationSettings = new ApplicationSettings() { UserCollectionName= "users" };
        _mockApplicationSettings.Setup(app => app.UserCollectionName).Returns(applicationSettings.UserCollectionName);
    

    Edit: Complete Example

        private Mock<IDatabaseSettings> _mockDbSettings;
        private Mock<IApplicationSettings> _mockApplicationSettings;
        private Mock<IMongoClient> _mockClient;
        public UserManagmentRepositoryTests()
        {
            _mockDbSettings = new Mock<IDatabaseSettings>();
            _mockApplicationSettings = new Mock<IApplicationSettings>();
            _mockClient = new Mock<IMongoClient>();
        }
    
        [Fact]
        public async Task GetUserWithId_Test()
        {
            // Arrange
            var repo = new Mock<IUserManagementRepository>();
            IDatabaseSettings dbSettings = new DatabaseSettings()
            {
                ConnectionString = "mongodb:connection",
                DatabaseName = "dbname"
            };
            _mockDbSettings.Setup(x => x.ConnectionString).Returns(dbSettings.ConnectionString);
            _mockDbSettings.Setup(x => x.DatabaseName).Returns(dbSettings.DatabaseName);
    
            IApplicationSettings applicationSettings = new ApplicationSettings() { UserCollectionName = "users" };
            _mockApplicationSettings.Setup(app => app.UserCollectionName).Returns(applicationSettings.UserCollectionName);
    
            MongoClientSettings clientSettings = MongoClientSettings.FromConnectionString(dbSettings.ConnectionString);
            MongoClient client = new MongoClient(clientSettings);
            _mockClient.Setup(c => c.GetDatabase(It.IsAny<string>(), It.IsAny<MongoDatabaseSettings>()))
                        .Returns <string, MongoDatabaseSettings>((name, settings) => client.GetDatabase(name, settings));
    
            var ctr = new UserManagementRepository(_mockDbSettings.Object, _mockApplicationSettings.Object, _mockClient.Object);
    
            // Act
            var result = await ctr.Get("132");
    
            // Assert
            result.ResponseCode.Should().NotBe(ResponseCode.Error);
        }
    
    Login or Signup to reply.
  2. You are trying to use ApplicationSettings as an expression. The setup method expects you to provide an expression for when to activate the mocked override.

    In your case just get rid of the Mock<IApplicationSettings> altogether and mock all the objects you need to call any methods on:

    [Fact]
    public async Task GetUserWithId_Test()
    {
      // Arrange
      var userModel = new UserModel() { Id = "123" };
    
      var mockCursor = new Mock<IAsyncCursor<UserModel>>();
      mockCursor
        .Setup(c => c.FirstOrDefault())
        .Returns(userModel);
    
      var mockCollection = new Mock<IMongoCollection<UserModel>>();
      Predicate<UserModel> filter = u => u.Id == userModel.Id;
      mockCollection
        .Setup(c => c.FindAsync(filter))
        .ReturnsAsync(mockCursor.Object);
    
      var mockDb = new Mock<IMongoDatabase>();
      mockDb
        .Setup(db => db.GetCollection<UserModel>(It.IsAny<string>()))
        .Returns(mockCollection.Object);
    
      _mockClient
        .Setup(c => c.GetDatabase(It.IsAny<string>()))
        .Returns(mockDb.Object)
    
      var ctr = new UserManagementRepository(new(), new(), _mockClient.Object);
    
      // Act
      var result = ctr.Get("132");
    
      // Assert
      result.StatusCode.Should().Be(ResponseCode.Success);
      result.Message.Should().Be("User exists!");
      result.Data.Should().Be(userModel);
    }
    
    

    Hope this helps a little 🙂

    Login or Signup to reply.
  3. I see no reason mocking IApplicationSettings and IDatabaseSettings you should go with :

     public class UserManagmentRepositoryTests
    {
        private Mock<IMongoClient> _mockClient;
        public UserManagmentRepositoryTests()
        {
            _mockClient = new Mock<IMongoClient>();
        }
    
        [Fact]
        public async Task GetUserWithId_Test()
        {
            // Arrange
            var repo = new Mock<IUserManagementRepository>();
            IDatabaseSettings dbSettings = new DatabaseSettings()
            {
                ConnectionString = "mongodb:connectionstring",
                DatabaseName = "dbname"
            };
    
            IApplicationSettings applicationSettings = new ApplicationSettings() { UserCollectionName = "users" };
    
            MongoClientSettings clientSettings = MongoClientSettings.FromConnectionString(dbSettings.ConnectionString);
            MongoClient client = new MongoClient(clientSettings);
            _mockClient.Setup(c => client);
    
            var ctr = new UserManagementRepository(dbSettings, applicationSettings, _mockClient.Object);
    
            // Act
            var result = ctr.Get("132");
    
            // Assert
            //result.StatusCode.Should().NotBeNull();
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search