开发者

Is it good practice to use Entity Framework in unit tests?

I'm writing NUnit tests for a service.

I've decided to do this by sending direct SQL statements to the database instead of using th开发者_开发技巧e Entity Framework model so that I could be certain of the results, i.e. I am testing what is in the database and not what the Entity Framework tells me is in the database (e.g. it could be reporting a cached result, etc.)

The only drawback is that it is getting tedious to write this code using SqlCommand, SqlDataReader, etc. and being able to use the EF model would be much easier.

How are others doing this? Is it good practice to use Entity Framework when writing tests or should direct calls to the database be used to ensure accurate results?


I would say it is a bad practice when testing the service cause it creates a dependency on the database.

What I did, was roll up my Model classes into a Repository pattern. The repository pattern was coded to an interface so that I could change the implementation of the database querying without effecting other parts of the code. It could be easily mocked and used for testing. This is the interface I constructed.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace App.Core.Repositories
{
    public interface IRepository<TKey, TModel>
        where TKey : IComparable
        where TModel : class
    {
        TModel Only(TKey key);
        IQueryable<TModel> Where(Func<TModel, bool> query);

        TModel Single(Func<TModel, bool> query);
        TModel First(Func<TModel, bool> query);
        IQueryable<TModel> All();

        void Insert(TModel entity);
        void Insert(IEnumerable<TModel> entities);

        void Update(TModel entity);
        void Update(IEnumerable<TModel> entities);

        void Remove(TModel entities);
        void Remove(Func<TModel, bool> query);
        void Remove(IEnumerable<TModel> entities);
    }

    public interface IRepository<TModel> : IRepository<int, TModel> where TModel : class { }

    public interface IRepository : IRepository<int, object> { }
}


Quite the opposite. The tests for our DA layer are not concerned about the database at all.

For example. We have a test that calls the Save method to save a new data object. It then calls the Load method to check that the object can be loaded back. I don't care weather that object was actually saved to the database or not, all I care about is that I can retrieve objects that were saved. If the EF wants to do some clever caching and not save immediately then that's fine by me.

Consider that in the future we might not use a SQL server back end any more, we might switch to oracle, or even a NOSQL solution. I don't want all my DA layer unit tests to break when I switch the back end. It's actually the reverse, I need my DA layer unit tests to continue to work unchanged so I can validate that the switch of the storage solution doesn't effect the semantics or use of the DA layer.


Well, let's put it this way: You shouldn't be writing unit tests to ensure that the Entity Framework itself works. That's Microsoft's job.

Also, some would argue that getting a SQL Server database in a "unit test" at all means that you are now doing integration testing rather than unit testing. This, regardless of how you do it. I'm not going to argue that point, though.

The unit tests that you write should be testing your own code.

You say that one of the reasons you want to read the database directly is that your application could be seeing cached data. Who wrote that cache? If it's you, then by all means unit test it, although I would probably mock out the database access in this case.

But if it's SQL Server's (or the Entity Framework's) caching you're concerned about, well, where would you begin? These products are huge, and there is no way that you're going to unit test the entire system.

This does not mean that you should presume that SQL Server and the Entity Framework are defect-free. But you typically catch errors in your framework via integration testing your application, rather than unit testing.


Instead of using LINQ to Entities, we use LINQ to SQL for Back Door Manipulation in our unit tests, as it's a little closer to the database schema.

However, instead of getting tired of doing all the SqlCommand, etc. stuff, we get tired of keeping the auto-generated L2S code in sync with the actual database...


As Craig and others already pointed out: You are doing Integration Testing.

Which means that I have to answer your main question with "No".

However, for your integrated testing, you might be doing more than fine to bypass any in-memory caching by using an EF context that is located in another appdomain. Every appdomain sees its own set of static values, so even if EF were to use a static cache in version 5(which I doubt), you could test it in a db-agnostic way. (repeating those tests for all backends your software supports.)

This is the paranoid version, btw. A second context should already do the trick.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜