Pragmatic unit testing with Entity Framework 6

 

In my current project we were first using a lot of mocking to be able to unit test. This resulted in a very time-consuming way of writing unit tests. After reading a blog post of Richard Garside, this got a whole lot easier.

The idea is simple, we provide a new implementation for DbSet that uses an in-memory store. Using this approach, we can use all the usual methods in a normal way without mocking all of them. We already had an interface for our DbContext, because we use Autofac for dependency injection.

Our DbContext interface

public interface IMyEntities
{
    IDbSet MyEntities { get; set; }    

    void Commit();

    void Dispose();

    void SetModified(object entity);

    System.Data.Entity.IDbSet<TEntity> Set() where TEntity : class;
}

Our actual DbContext implementation
The actual implementation of the DbContext implements the interface, so we can easily provide another implementation for our unit tests:

public class MyEntities : DbContext, IMyEntities
{
    public IDbSet MyEntities { get; set; }

    public virtual void Commit()
    {
        base.SaveChanges();
    }

    public IDbSet<T> Set<T>() where T : class
    {
        return base.Set<T>();
    }

    public void SetModified(object entity)
    {
        Entry(entity).State = EntityState.Modified;
    }
}

In-memory DbContext implementation
The implementation of our in-memory DbSet is displayed below. In the constructor we set each entity set we use to a specific Fake implementation. We will get to that in a bit.

public class FakeMyEntities : DbContext, IMyEntities
{
    public FakeMyEntities()
    {
        MyEntities = new FakePersonSet();
    }

    public IDbSet MyEntities { get; set; }

    public virtual void Commit()
    {
    }

    public IDbSet<T> Set<T>() where T : class
    {
        foreach (PropertyInfo property in typeof(FakeMyEntities).GetProperties())
        {
            if (property.PropertyType == typeof(IDbSet<T>))
                return property.GetValue(this, null) as IDbSet<T>;
        }
        throw new Exception("Type collection not found");
    }

    public void SetModified(object entity)
    {
    }
}

In-memory DbSet base and specific sets

The base class for all FakeDbSets looks like this:

public class FakeDbSet<T> : IDbSet<T>
    where T : class
    {
        HashSet<T> _data;
        IQueryable _query;

        public FakeDbSet()
        {
            _data = new HashSet<T>();
            _query = _data.AsQueryable();
        }

        public virtual T Find(params object[] keyValues)
        {
            throw new NotImplementedException("Create a Fake(object)Set in Pegasus.Tests.Infrastructure.FakeSet");
        }

        public T Add(T item)
        {
            _data.Add(item);
            return item;
        }

        public T Remove(T item)
        {
            _data.Remove(item);
            return item;
        }

        public T Attach(T item)
        {
            _data.Add(item);
            return item;
        }
        public T Detach(T item)
        {
            _data.Remove(item);
            return item;
        }
        Type IQueryable.ElementType
        {
            get { return _query.ElementType; }
        }
        System.Linq.Expressions.Expression IQueryable.Expression
        {
            get { return _query.Expression; }
        }

        IQueryProvider IQueryable.Provider
        {
            get { return _query.Provider; }
        }
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _data.GetEnumerator();
        }
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return _data.GetEnumerator();
        }

        public TDerivedEntity Create() where TDerivedEntity : class, T
        {
            throw new NotImplementedException("Derive from FakeDbSet and override Create");
        }

        public T Create()
        {
            throw new NotImplementedException("Derive from FakeDbSet and override Create");
        }

        public System.Collections.ObjectModel.ObservableCollection<T> Local
        {
            get { throw new NotImplementedException("Derive from FakeDbSet and override Local"); }
        }
    }

All we have to do now for each entity set, is to create a FakeDbSet and implement the Find method, as the primary key can be different for each Model object.

public class FakePersonSet : FakeDbSet
    {
        public override Order Find(params object[] keyValues)
        {
            return this.SingleOrDefault(e => e.SocialSecurityNumber == Convert.ToInt32(keyValues.Single()));
        }
    }

Now you just have to make sure that your unit tests use the FakeDbContext instead of the real one, and your code will just work. It requires a bit of setup, but once this works, writing your unit tests is a lot easier.

 

GTD in Evernote

Bij de implementatie van Getting Things Done (GTD) kwam ik al snel uit bij het selecteren van een tool. Ga ik de lijstjes op papier bijhouden, of toch een applicatie? Ga ik prive en zakelijk mixen, of net niet? Zet ik mijn lijstjes in outlook, of toch todoist, remember the milk, of evernote?

Sinds ik het Getting Things Done boek van David Allen in mijn handen kreeg heb ik talloze applicaties geprobeerd. Na jaren zoeken bestaat de ‘perfecte’ tool voor mij nog steeds niet, en wilde ik een langere tijd mijn energie eens steken in het proces in plaats van de tool. Ik nam  me voor om een jaar lang dezelfde applicatie voor mijn GTD proces te gebruiken.

Mijn keuze is toen gevallen op Evernote. Evernote is niet direct een taakapplicatie, maar kan er wel voor gebruikt worden. Evernote is een zeer flexibele applicatie, en kan dan ook op meerdere manieren gebruikt worden voor het GTD proces. Deze post toont kort de mogelijke manieren om Evernote als GTD tool te gebruiken.

Tags of notebooks?

Een GTD implementatie in Evernote kan op verschillende manieren:

  • Notebooks gebruiken (in combinatie met notebook stacks) voor lijstjes
  • Tags gebruiken voor lijstjes
  • Een combinatie van beiden

Notebooks

Notebooks gebruiken in Evernote voor je actielijstjes ziet er bijvoorbeeld zo uit:

EvernoteNotebooks

De bekende lijstjes in GTD zoals @Computer, @Calls en @Home zijn hier gebundeld in een Notebook Stack.
David Allen adviseert in zijn eigen Evernote handleiding aan om Evernote op deze manier in te richten. Dit is inderdaad de simpelste oplossing, vooral als je niet bekend bent met de tagging functionaliteit in Evernote.

Tagging

Een aanpak genaamd The Secret Weapon bied een geheel andere aanpak. Deze opzet gebruikt 1 notebook en werkt volledig met een gelaagde tag structuur. Veel aanhangers van Evernote zweren bij taggen, deze implementatie past hier een stuk beter bij. Op de site staan diverse filmpjes die je laten zien hoe je je systeem kunt inrichten.

EvernoteTags

Wat is nu beter?

Uiteindelijk gaat het om wat voor jou fijner aanvoelt. Ik heb ze beiden geprobeerd, momenteel gebruik ik de simpelere notebook aanpa weer. Beide inrichtingen werken echter prima. Op een mobiel device kan het zijn dat beide inrichtingen wel net iets anders weergegeven worden, dit ligt een beetje aan het mobiele platform dat je gebruikt. Als je nieuw bent in Evernote, is de eerste aanpak wat laagdrempeliger om mee te beginnen, en kun je later eens wat tags gaan gebruiken om te kijken hoe dat werkt. Het is echter geheel persoonlijk.