Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NHibernate Unit Testing Mocking/In Memory Database

I am trying to learn how to mock my generic repository so i can unit test all my services.

Im using NHibernate Fluent to handle data access and a Ninject for dependency (I'm not interested in testing that)

My repository interface looks like:

public interface IRepository<TEntity>  where TEntity : class 
{
    IQueryable<TEntity> GetAll();
    TEntity Get(int key);
    void Insert(TEntity entity);
    void Update(TEntity entity);
    void Delete(int id);
}

And the actual repository looks like:

public class GenerRepository<TEntity> : IRepository<TEntity>where TEntity : Entity
{
    protected ISession Session{get { return NHibernateHelper.OpenSession(); }}
    public IQueryable<TEntity> GetAll(){return Session.Query<TEntity>();}
    public TEntity Get(int key){return Session.Get<TEntity>(key);}
    public void Insert(TEntity entity){Session.Save(entity);}
    public void Update(TEntity entity){Session.Update(entity);}
    public void Delete(int id){Session.Delete(Session.Load<TEntity>(id));}
}

All my services do the following take the created repository in and use it.

I've read so many articles on how to do this but none are simple or well explained. So any advice between creating a test generic repository or even mocking it. I would also be interested in creating a in memory database but how do i set the configuration up for fluent nhibernate in my test project without editing code in my real project?

Is it possible just to make the generic repository hit a list of Tentity rather than the database or in memory database.

Thanks for reading and look forward to the advice.

like image 660
Lemex Avatar asked Dec 21 '13 16:12

Lemex


People also ask

Should I use in memory database for testing?

This database provider allows Entity Framework Core to be used with an in-memory database. While some users use the in-memory database for testing, this is generally discouraged; the SQLite provider in in-memory mode is a more appropriate test replacement for relational databases.

Should you mock a database?

Mocking and stubbing are the cornerstones of having quick and simple unit tests. Mocks are useful if you have a dependency on an external system, file reading takes too long, the database connection is unreliable, or if you don't want to send an email after every test.

What can be mocked with MOQ?

You can use Moq to create mock objects that simulate or mimic a real object. Moq can be used to mock both classes and interfaces.


2 Answers

My answer should/could be a comment, maybe. Because I would like to tell you: do not do it. Do not waste your time to create a fake of the data to be returned from persistence. And do not invest your time to: take the data from a client and put them into some virtual DB in memory.

You need to be sure, that your services (consuming repository) can really serialize/render the real data. And deserialize/persist the changed. And that would really require a real data.

Rather spend some time to create scripts, which will populate the test data. The data which you can expect in your tests: when doing Business validation, Service data serialization...

Also take a look here: Ayende: NHibernate Unit Testing. An extract:

When using NHibernate we generally want to test only three things, that properties are persisted, that cascade works as expected and that queries return the correct result. In order to do all of those, we generally have to talk to a real database, trying to fake any of those at this level is futile and going to be very complicated.

A note: some time ago, we used to wrap all the tests in Transaction Begin() and Rollback(). Which was looking good. But we realized, that lot of stuff - because of missing Flush() call - was not tested all the way down (e.g. setting not-null).

like image 71
Radim Köhler Avatar answered Sep 27 '22 19:09

Radim Köhler


I have to agree with Radim, that unit testing nhibernate code by mocking the nhibernate functionality in most cases in not what you want to do.

Unless you want to test complex business logic which is based on data you retrieve via nhibernate, then this is perfectly fine.

But to test if your mappings, data retrieval and persistence works fine, you have to test against a real database.

If you target MSSQL Server, I would not use another type of database. Instead there is SQL Express which has all features of the real server. MSSQL Express can optionally be installed with local DB. This will allow you to load mdf files via connection string which will more or less instantiate an instance of MSSQL Server...

I used that for integration testing and it works really nice.

  1. Create a data base file in your unit test project
  2. Depending on your model (code first/db first) let nhibernate create the scheme, otherwise simple populate the scheme into that database file
  3. Add the file to the deployment items of your test settings so that the file gets copied to the test target directory
  4. Generate a connection string which uses the copied database file. Example connection string: Data Source=(LocalDB)\v11.0;AttachDbFileName=[whateverthepathis]\DatabaseFileName.mdf;InitialCatalog=DatabaseName;Integrated Security=True;MultipleActiveResultSets=True
  5. Run your tests

This way your tests will run with an empty database every time and you will have reproduceable integration tests without the need of a real server where you would have to create a DB or reset it everytime...

like image 24
MichaC Avatar answered Sep 27 '22 19:09

MichaC