Quote in The Art Of Unit Testing by Roy Osherove:
There is no object-oriented problem that cannot be solved by adding a layer of indirection, except, of course, too many layers of indirection.
Below is my mockable EF4 POCO setup. I didn't use T4 as it was too hard to work out how to clean up the template to not generate too much gumpf. You can of course hack the T4 template to spit out something like this structure.
The trick was to create the ObjectSet<T>
s manually and expose them as IQueryable
. Because Add
and Create
are on ObjectSet<T>
/ObjectSet<T>
, I also had to add methods for adding and creating entities.
public interface IStackTagzContext {
IQueryable<Question> Questions { get; }
Question CreateQuestion();
void CreateQuestion(Question question);
void SaveChanges();
}
public class StackTagzContext : ObjectContext, IStackTagzContext {
public StackTagzContext() : base("name=myEntities", "myEntities")
{
base.ContextOptions.LazyLoadingEnabled = true;
m_Questions = CreateObjectSet<Question>();
}
#region IStackTagzContext Members
private ObjectSet<Question> m_Questions;
public IQueryable<Question> Questions {
get { return m_Questions; }
}
public Question CreateQuestion() {
return m_Questions.CreateObject();
}
public void AddQuestion(Question question) {
m_Questions.AddeObject(question);
}
public new void SaveChanges() {
base.SaveChanges();
}
#endregion
}
Now, you will note that the entity collection type on the interface is IQueryable<T>
, as opposed to IObjectSet<T>
. I couldn't be bothered creating FakeObjectSet
and IQueryable
provided me with enough flexibility. So in order to KISS, I've managed without it.
Mocking IQueryable
, on other hand, is trivial:
using Moq;
[TestClass]
public class TestClass {
Mock<IStackTagzContext> m_EntitiesMock = new Mock<IStackTagzContext>();
[TestMethod()]
public void GetShouldFilterBySite() {
QuestionsRepository target = new QuestionsRepository(m_EntitiesMock.Object);
m_EntitiesMock.Setup(e=>e.Questions).Returns(new [] {
new Question{Site = "site1", QuestionId = 1, Date = new DateTime(2010, 06,23)},
}.AsQueryable());
}
}