Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongodb unit testing in .NET

I am trying to do tdd and use mongodb as database. But i cant resolve problem of mocking mongodb. Is there any ability to mock mongodb for unit testing in .NET?


Update

I found very good soltion reading blog. You can find it here:

like image 823
F0rc0sigan Avatar asked Oct 09 '12 16:10

F0rc0sigan


People also ask

Can we use MongoDB with .NET core?

If you haven't already, install . NET Core 3.1 or above and install your preferred IDE (Visual Studio or VS Code) . Create a MongoDB database. The easiest way to get started with MongoDB is to create a free cluster in MongoDB Atlas, MongoDB's fully-managed, multi-cloud document database service.

Can I use MongoDB with ASP NET?

If you want to download the source code, you can do that on our ASP.NET Core and MongoDB repo. To help us build a web API with a schema-less database, we'll look at how to set up an ASP.NET Core application with MongoDB.

What is .NET unit testing?

Unit testing breaks the program down into the smallest bit of code, usually function-level, and ensures that the function returns the value one expects. By using a unit testing framework, the unit tests become a separate entity which can then run automated tests on the program as it is being built.

What is Mongo2Go?

Mongo2Go is a managed wrapper around the latest MongoDB binaries. It targets . NET Standard 2.0 (and . NET 4.6 for legacy environments) and works with Windows, Linux and macOS. This Nuget package contains the executables of mongod, mongoimport and mongoexport for Windows, Linux and macOS .


3 Answers

Instead of mocking MongoDB, you should be mocking a layer on top of MongoDB.

You might want to consider an interface that exposes the operations on your repository which are agnostic to the underlying data store. For example, you might want an interface that abstracts out operations on Student types, like so:

public interface IStudentOperations
{
    void Add(Student student);
}

When you create your other dependencies, you inject instances of the above interface, or whichever higher-level abstractions you choose.

The point is, don't expose MongoDB directly.

Once you do that, you can mock the interfaces you create all you want, having one implementation for testing against the mock implementation, and then an actual implementation with it's own tests to validate that operations on the implementation are correct when the underlying implementation is with MongoDB.

While it's definitely possible to mock most of MongoDB's classes (as the methods are virtual), you gain the benefit of being persistence agnostic; if you want to switch to say, CouchDB or elasticsearch, you don't have to change the calls to these interfaces, you simply create a new implementation.


Because you are trying to test the implementation of the repository, then you are generally fine, as has been stated before, most of MongoDB's functions are virtual, which is friendly to most mocking libraries.

That said, you'll have to make sure that you pass the MongoDatabase into your repository (not create it in the repository) so that in your unit tests, you can create the appropriate mock and then pass it into your repository implementation for testing.

like image 105
casperOne Avatar answered Oct 19 '22 11:10

casperOne


You need a repository/DAL layer to hide implementation details. Something like this:

public interface IDataContext<T>
{
   // Query
   IList<T> GetAll<T>();
   IList<T> GetByCriteria<T>(Query query);
   T GetByID<T>(string id);

   // CUD
   void Add(T item);
   void Delete(T item);
   void Save(T item);
}
  • For production code, implement the interface with mongo db operations with the assistance of C# driver
  • For unit test codes, mock the interface with an in-memory collection

It looks straightforward to mock Add/Delete/Save, and the intersting part is query function. Fortunately, since mongo C# driver supports LINQ expressions, we can use LINQ as the query language rather than reinventing the wheels.

For example, the production code may look like:

// collection is a MongoCollection<T> object
var items = collection.AsQueryable().Where(...linq expression...);

And unit test code (if you go with Shim, MS test):

using (ShimsContext.Create())
{                  
    ShimLinqExtensionMethods.AsQueryableOf1MongoCollectionOfM0(
        (MongoCollection<T> x) => Fake_DB_Collection.AsQueryable());
    // After this, the above "collection.AsQueryable()" will be mocked as 
    // an in-memory collection, which can be any subclass of IEnumerable<T>             
} 
like image 20
David Hu Avatar answered Oct 19 '22 11:10

David Hu


See this similar question: Mocking database in node.js?

In short, mocking MongoDB isn't the right approach. Mocking your repository is adequate for testing your own units, but you'll still need to test against MongoDB if you want to make sure that you're using it correctly, or if you are relying on uniqueness constraints etc.

like image 2
cirrus Avatar answered Oct 19 '22 11:10

cirrus