Dad of Many
Dad of Many

Reputation: 21

Unit testing with FakeItEasy against nested Entity Framework member

We are trying to unit test code that relies on the Entity Framework 4.1. I've seen several posts that implement unit testing against POCOs, but we would like to retain the default EF plumbing, so that we can easily use the EF Caching Wrapper.

FakeItEasy seems to handle abstracting away EF okay, but I'm having problems asserting what happened. For example, I have this code in my model (where there is another Email partial class that is the autogenerated code from the EF database-first wizard):

public partial class Email 
{
    IMyEntities _dataContext;

    public Email(IMyEntities myEntities)
    {
        _dataContext = myEntities;
    }
    public void SendEmails()
    {
        // ... code to send emails goes here...
        _dataContext.Emails.AddObject(this);
        _dataContext.SaveChanges();
    }
}

Then in my unit test with FakeItEasy:

var context = A.Fake<IMyEntities>();
var email = A.Fake<Email>(context);
// ... code to configure email goes here ...
email.SendEmails();

// this fails with a FakeItEasy.ExpectationException...
A.CallTo(() => context.Email.AddObject(email)).MustHaveHappened();

How can I know from my unit test that context.Emails.AddObject actually did get called?

Thank you!

Upvotes: 1

Views: 1883

Answers (2)

Patrik H&#228;gne
Patrik H&#228;gne

Reputation: 17151

You need to set the Email-property of you context to a fake:

var context = A.Fake<IMyEntities>();
var mail = A.Fake<WhateverTypeTheEmailPropertyHas>();
A.CallTo(() => context.Email).Returns(mail);

var email = A.Fake<Email>(context);
// ... code to configure email goes here ...
email.SendEmails();

// this fails with a FakeItEasy.ExpectationException...
A.CallTo(() => mail.AddObject(email)).MustHaveHappened();

Now I guess it should work.

Upvotes: 1

Dad of Many
Dad of Many

Reputation: 21

I found a workaround that I'm not crazy about, but it does work. Instead of calling AddObject() on the child object, you can call a deprecated method, AddTo[Collection Name](), on the data context itself. Since this is just a shallow method call, it can be easily evaluated by FakeItEasy.

My code changed to this:

public void SendEmails()
{
    // ... code to send emails goes here...
    _dataContext.AddToEmails(this);
    _dataContext.SaveChanges();
}

Then, in my unit test:

A.CallTo(_dataContext).Where(m => m.Method.Name == "AddToEmails").MustHaveHappened();
A.CallTo(() => _dataContext.SaveChanges()).MustHaveHappened();

Of course, by doing this you have the downside of always ignoring the preferred, non-deprecated, methods whenever you want to add to a collection of the data context. Not to mention, there's a good chance I'll get tripped up later on with a need to determine execution on a child object's method...

If anyone knows a better way, please share!

Thank you,

Eric

Upvotes: 0

Related Questions