0

We are trying to figure out what the point of unit testing is for basic cases as in the code below. Does making a unit test for this beneficial ? We are not trying to test the entity framework. We just want to make sure the lambda expression does what it should... Our idea is that we will use DI to pass in SOMETHING that is IQueryable.. In practice it will be EF but for unit tests and will be POCO objects/collections. Does this makes sense ? We are just getting started and want to master the concepts before we get beyond this basic code.

   public class CongressRepository
{
    CongressDb_DevEntities context = new CongressDb_DevEntities();

    CongressRepository(DbContext db)
    {
        context = (CongressDb_DevEntities) db;
    }

    public IQueryable<tMember> GetAllMembers
    {
        get { return context.tMembers; }
    }

    public IQueryable<tMember> GetVotingMembers
    {
        get { return context.tMembers.Where(x => x.age > 18); }
    }
}
punkouter
  • 5,170
  • 15
  • 71
  • 116
  • Sooo you're asking us if you should unit test these methods? These tests will be written quickly and it doesn't hurt to get used to them if you're new to writing tests. I don't see why you specifically mention lambdas/EF though, what exactly is it that you have a question about? – Jeroen Vannevel Oct 18 '13 at 20:55
  • We know we should.. I guess it was not clear.. We are asking how... What I mean is can we manually create collections of objects from the auto generate DbContext stuff... and will THOSE be queryable in exactly the same way as the default EF DbContext behavior ? – punkouter Oct 18 '13 at 20:59

3 Answers3

5

EF uses LINQ to Entities, but when mocking EF you'd be switching to LINQ to Objects. This could lead to false positives in terms of your unit tests as there are differences between LINQ to Entities and LINQ to Objects. Without integration tests, you'd only see these differences / errors in your production environment.

Martin4ndersen
  • 2,806
  • 1
  • 23
  • 32
  • So you are saying the way people normally do this is to MOCK the objects that do the querying and then unit the rest of the code? In the case of GetAllMembers() there is nothing left of the code after you MOCK it.. so then.. I guess I do not unit test that kind of method ? – punkouter Oct 21 '13 at 15:57
  • In TDD you wouldn't have the method until you had the tests. The tests would describe what GetAllMembers result should be for known data. Which helps protect against changes with unintended side effects in future... – Paul D'Ambra Oct 23 '13 at 14:13
2

One of the reasons for unit testing code is ensuring accuracy...

In your example someone could not vote on their 18th birthday or any of the days between it and their 19th birthday. I'm guessing it should really be:

public IQueryable<tMember> GetVotingMembers
{
    get { return context.tMembers.Where(x => x.age >= 18); }
}

Unit tests which cover a range of reasonable successful and failing values help ensure that your code does what you meant it to :-)


but what we are trying to find a why to ask is how the unit tests work.

It can be a real pain! EF6 has just been announced and makes it easier to mock the DbContext but right now it takes a lot of setup...

The important things is that there are differences between Linq-to-Etities and Linq-to-Objects so you do need both unit testing and integration testing.

There are lots of blogs and SO questions related though... use FakeDbSet as a starting point for some google-fu.

Community
  • 1
  • 1
Paul D'Ambra
  • 7,629
  • 3
  • 51
  • 96
  • 1
    Yes. We know we should unit test. And this is a great example for starters .. but what we are trying to find a why to ask is how the unit tests work... EF vs. manual EF ? It is hard for us to find a way to explain this... We are trying to UNIT test.. and not INTEGRATION test – punkouter Oct 18 '13 at 21:01
  • so like I mentioned above.. is it really overkill to worry about emulating DbContext with linqToObjects? And is it better just to MOCK that.. and save unit tests for methods that do something more advanced that 'Give me all of a particular entity' ? – punkouter Oct 21 '13 at 15:59
  • Since you're wrapping DbContext then yes you should have a mechanism for asserting the class that has DbContext returns expected values for known data. Some people will only use something like SQLce others will unit test against a mock *and* have an integration test against a database – Paul D'Ambra Oct 22 '13 at 18:22
  • but using sqlCE is 'integration testing' right? and 'unit testing' is using POCO/mocks ? though I don't see anything wrong with just using a test DB that I startup, add objects and tear down.. Once I have the test data in it I can use that.. which eliminates the problem of using linq2objects.. I guess what I am wondering is should there be distinct unit test and distinct integration tests or could I just combine them as mention above since maybe its more practical ? comments ? – punkouter Oct 23 '13 at 13:31
  • 1
    It depends on your system. You definitely shouldn't only have unit tests. There are reasonable concerns around the speed of running the database setup and tear down for all of your tests. If that isn't a significant cost for your system then you can survive with just tests against a DB. – Paul D'Ambra Oct 23 '13 at 14:11
1

For unit testing an object that uses DbContext, you will have to inject it as an interface into your repository object. Follow these steps:

1.Create an interface that contains all DbContext properties, and derive your DbContext from it:

 public interface ICongressDbContext {
    IDbSet<Member> Members { get; set; }
    // repeat for all dbsets
 }

2.Give this interface to your repository in the constructor. This is your dependency injection:

 private ICongressDbContext context;
 public CongressRepository(ICongressDbContext context){
     this.context = context;
 }

You will want to pass an instance of the context in using a dependency injection framework like Autofac, or you can create an instance where you instantiate your object.

3.Create a generic implementation of IDbSet: https://gist.github.com/LukeWinikates/1309447. Let's call this FakeDbContext.

4.Now that you have a mockable interface, and a generic DbSet implementation, you are ready to create your mock DbContext and your mock IDbSets. Using Moq, this looks like:

        var dataContext = new Mock<ICongressDbContext>();
        var members = new List<Member> { // create your test data here };
        // set up the mocked context to use your fake db set with test data
        dataContext.SetupProperty(c => c.Members, new FakeDbContext<Member>(members));

        var repository = new CongressRepository(dataContext.Object);

        // start writing your test methods here

This will test the object that uses the DbContext, not the DbContext itself.
You will want to write integration tests that use the real DbContext in addition to the unit tests. There are many methods supported on IQueryable that are not supported when accessing the database. You also want to make sure your data model is mapped correctly to the database.

I hope this helps you to get started.

gabnaim
  • 1,103
  • 9
  • 13
  • ok. This seems like the route to go.. even though line2objects is different than linq2ent.. maybe its close enough – punkouter Oct 22 '13 at 15:12