Tutorial :Unit testing a LINQ2SQL repository



Question:

I am taking my first steps with MsTest and Moq and would like to unit test a Linq2SQL repository class. The problem is that I do not want the unit tests to permantly modify my development database.

Which would be the best approach for this scenario?

  • Let each test operate on my real development database, but make sure each test cleans up after itself
  • Create a duplicate of my development database and dbml for the unit test and use that context instead so I can clear the entire database before each test run
  • Find some elaborate way of mocking the Datacontext (please bear in mind that I am a total Moq noob).
  • Something completely different? Perhaps something that would automate setting up the database for me before each test run?

Edit: I just learned that MBUnit has a rollback attribute that reverses any database operations run by a test case. I am not particularly attached to MSTest, so could this be an easy answer to my problem?


Solution:1

I went with mocking/faking the database using some wrapper classes + a fake implementation based on http://andrewtokeley.net/archive/2008/07/06/mocking-linq-to-sql-datacontext.aspx. Note that I did end up implementing SubmitChanges logic in my fake data context wrapper to test out the validation logic in my entity's partial class implementation. I think that this was really the only tricky part which differed substantially from Tokeley's implementation.

I'll include my FakeDataContextWrapper implementation below:

public class FakeDataContextWrapper : IDataContextWrapper  {        public DataContext Context      {          get { return null; }      }        private List<object> Added = new List<object>();      private List<object> Deleted = new List<object>();        private readonly IFakeDatabase mockDatabase;        public FakeDataContextWrapper( IFakeDatabase database )      {          mockDatabase = database;      }        protected List<T> InternalTable<T>() where T : class      {          return (List<T>)mockDatabase.Tables[typeof( T )];      }        #region IDataContextWrapper Members        public virtual IQueryable<T> Table<T>() where T : class      {          return mockDatabase.GetTable<T>();      }        public virtual ITable Table( Type type )      {          return new FakeTable( mockDatabase.Tables[type], type );      }        public virtual void DeleteAllOnSubmit<T>( IEnumerable<T> entities ) where T : class      {          foreach (var entity in entities)          {              DeleteOnSubmit( entity );          }      }        public virtual void DeleteOnSubmit<T>( T entity ) where T : class      {          this.Deleted.Add( entity );      }        public virtual void InsertAllOnSubmit<T>( IEnumerable<T> entities ) where T : class      {          foreach (var entity in entities)          {              InsertOnSubmit( entity );          }      }        public virtual void InsertOnSubmit<T>( T entity ) where T : class      {          this.Added.Add( entity );      }        public virtual void SubmitChanges()      {          this.SubmitChanges( ConflictMode.FailOnFirstConflict );      }        public virtual void SubmitChanges( ConflictMode failureMode )      {          try          {              foreach (object obj in this.Added)              {                  MethodInfo validator = obj.GetType().GetMethod( "OnValidate", BindingFlags.Instance | BindingFlags.NonPublic );                  if (validator != null)                  {                        validator.Invoke( obj, new object[] { ChangeAction.Insert } );                  }                  this.mockDatabase.Tables[obj.GetType()].Add( obj );              }                this.Added.Clear();                foreach (object obj in this.Deleted)              {                  MethodInfo validator = obj.GetType().GetMethod( "OnValidate", BindingFlags.Instance | BindingFlags.NonPublic );                  if (validator != null)                  {                      validator.Invoke( obj, new object[] { ChangeAction.Delete } );                  }                  this.mockDatabase.Tables[obj.GetType()].Remove( obj );              }                this.Deleted.Clear();                foreach (KeyValuePair<Type, IList> tablePair in this.mockDatabase.Tables)              {                  MethodInfo validator = tablePair.Key.GetMethod( "OnValidate", BindingFlags.Instance | BindingFlags.NonPublic );                  if (validator != null)                  {                      foreach (object obj in tablePair.Value)                      {                          validator.Invoke( obj, new object[] { ChangeAction.Update } );                      }                  }              }          }          catch (TargetInvocationException e)          {              throw e.InnerException;          }      }        public void Dispose() { }        





        
Previous
Next Post »