OrthoCoders

You can code it, I can help!

Beware of PowerPoint Architects

I'm reading the book Manage It! and found this excerpt that talks about seagull architects. I hope you like it.
I've worked on several projects where the architect was like a seagull. He swooped in, dumped a lot of poop in the form of PowerPoint pictures of the architecture, and left as soon as possible. He didn't stick around for the hard part of the project: making the product work in this architecture or evolving the architecture so that the product could work by the time of release.2 But if your architect is overly fond of drawing programs and not fond of writing code and can't really answer the developers' questions about how to make the parts fit into a coherent structure, you don't have a real architect. Eliminate that person from your project, and build time into the project for assessing the architecture as you proceed. Add the lack of architecture as an explicit risk to your project so you can manage it. Not every project requires an architect. If you have no architect, your sponsors should recognize that your team needs time to assess the architecture and see what patterns are emerging. It's possible to have an architect who acts as a consultant to the project. It is harder when you have a consultant-architect—Murphy's Law implies that the architect will be busy on another higher-priority project when you need him or her most.

TDD @ the Winnipeg .NET User Group

On Feb 17th I'm going to do a presentation about TDD with the Winnipeg .NET user group. The presentation will explain the benefits of using TDD and how to start. I'm planning to talk about code coverage, mocking, which tools are available and how they make our testing easier. I'll post the presentation as soon I have it ready. Here is the information about the event. See u there!

Database Testing Automation

Why testing?

If you are wondering why you should test your code or why using Test Driven Development is a great advantage then please check Wikipedia, AgileData and Kent Beck's book. If you are convinced so far, please read on.

Testing Automation

Writing tests allow us to prove that our code work as expected. Having tests written also allow us to run all our tests every time new code is added to make sure that nothing broke so far. Continuous Integration is a common practice used to build, test and deploy every time the code changes in the repository. Because the build script is run from our CI server,  our tests should be designed and written to run without external dependencies or with few as possible. If you want to read more about continuous integration you can read Martin Fowler's article about it.

I have a DB, where should I start?

First of all we need to model our Data Access Layer (DAL for short) to provide access to the storage. The DAL provides the interfaces and classes that will abstract our application from our target storage. Thus if we decide to use LINQ to SQL or ADO Entity Framework or Castle ActiveRecord as implementation the DAL does not change and does not impact the rest of our application. Different needs may require different DAL implementations, we can even use REST services to access our storage with the same DAL. As an example to illustrate the testing let's imagine we have a DAL to represent a media library. A media library is a library that stores DVDs, games, music for a user. Here is a small diagram to describe the structure I'm planning to use:

DAL Diagram DbTest

DAL, SHMAL, what about testing?

So far, so good. We have our DAL and before writing our first class, let's think about what we need to write the test. The test should check that our concrete DAL implementation is querying/modifying the database in the expected way. In order to do that, I can think of the following requirements:
  • Try to minimize dependencies (if possible) with the database in order to run the test stand alone.
  • Each test should start from a valid clean database (need a way of create/drop the schema).
  • The database should be deleted after the tests are done.
Because we have the same requirements for all our tests I think a base class would suit our needs and provide common functionality. Let's call it BaseDbTest. To fulfill our requirements I'm going to take advantage of MbUnit initialization and clean up events:
  • FixtureSetUp: Runs before all the tests in the class are run.
  • SetUp: Runs before each test is run.
  • TearDown: Runs after each test is run.
  • FixtureTearDown: Runs after all the test in the class are run.
So, how to use these events for our goal? Let's see:
  • FixtureSetUp: Create the database and initialize framework.
  • SetUp: Create the schema and populate the database.
  • TearDown: Drop the schema.
  • FixtureTearDown: Drop database.
And here is the code for the test:
        /// 
        /// Creates the schema for an empty database
        /// 
        [SetUp]
        public void BeforeEachTest()
        {
            CreateSchema();
        }

        /// 
        /// Drops the schema to clean the database
        /// 
        [TearDown]
        public void AfterEachTest()
        {
            DropSchema();
        }

        /// 
        /// Creates a temporary database using a temporary file name and
        /// initializes the entities using the connection string to that database
        /// 
        [FixtureSetUp]
        public void BeforeAllTheTests()
        {
            CreateDatabase();
            InitializeFramework();
        }

        /// 
        /// Clears up the resources and deletes the database file used
        /// 
        [FixtureTearDown]
        public void AfterAllTheTests()
        {
            DeleteDatabase();
        }
That's a good start. Now we have to think about which database we are going to use for the testing. Because we would like to minimize the dependencies with any database in order to run the tests in any environment I'm going to use a SQL CE database. SQL CE uses a file as storage and we can generate the file when we need it and then delete it. So here is the implementation to create and delete the database using SQL CE:
        /// 
        /// Creates the database file using a temporary file name
        /// 
        private void CreateDatabase()
        {
            this.DatabaseFileName = Path.GetTempFileName();

            DeleteDatabase();
            
            var engine = new SqlCeEngine(this.ConnectionString);

            engine.CreateDatabase();
        }

        /// 
        /// Deletes the database file
        /// 
        private void DeleteDatabase()
        {
            File.Delete(this.DatabaseFileName);
        }

        /// 
        /// Filename to use for the database
        /// 
        protected string DatabaseFileName { get; set; }
Now, we need to create/drop the schema and initialize the framework. To do that we need to chose which framework we are going to use, in this case I'm using Castle ActiveRecord to do it:
        /// 
        /// Creates the schema to run the tests
        /// 
        virtual protected void CreateSchema()
        {
            // log the creation script
            // ActiveRecordStarter.GenerateCreationScripts( "c:\\temp\\create.sql");

            ActiveRecordStarter.CreateSchema();
        }

        /// 
        /// Connection string to use
        /// 
        protected string ConnectionString 
        { 
            get
            {
                return String.Format( "Data Source={0};", this.DatabaseFileName);
            }
        }

        /// 
        /// Creates the properties and initializes the framework using ActiveRecordStarter
        /// 
        private void InitializeFramework()
        {
            var properties = new Dictionary<String, String>
                                 {
                                     //{"hibernate.show_sql", "true"},
                                     {"hibernate.connection.driver_class", "NHibernate.Driver.SqlServerCeDriver"},
                                     {"hibernate.dialect", "NHibernate.Dialect.MsSqlCeDialect"},
                                     {"hibernate.connection.provider", "NHibernate.Connection.DriverConnectionProvider"},
                                     {"hibernate.connection.connection_string", this.ConnectionString}
                                 };

            var source = new InPlaceConfigurationSource();

            source.Add( typeof(ActiveRecordBase), properties);

            ActiveRecordStarter.ResetInitializationFlag();

            ActiveRecordStarter.Initialize( typeof( MediaElement ).Assembly, source );
        }

        /// 
        /// Drops the schema after running the tests
        /// 
        virtual protected void DropSchema()
        {
            ActiveRecordStarter.DropSchema();
        }

Voilá, that's it. Castle ActiveRecord provides a very convenient way of creating and dropping the schema using the ActiveRecordStarter class. Be mindful that the InitializeFramework runs once before per test class, thus we need to reset the initialization to avoid error messages using ActiveRecordStarter.ResetInitializationFlag().

Last but not least, our first test

To test our implementation let's start with IMediaLibrary implementation to check that the following cases are true:
  • When calling Contents all the media in the database is returned.
  • When calling Users all the users in the database are returned.
  • When adding media to the library the media is stored
Without further ado:
        /// 
        /// Tests that all the users in the database are returned
        /// 
        [Test]
        public void WhenAskingForTheUsersAllTheUsersShouldBeReturned()
        {
            var expected = factory.LotsOf<IUser>();

            var actual = this.mediaLib.Users;

            Assert.IsNotNull( actual, "The users should not be null" );

            var eSorted = expected.OrderBy(e => ((User)e).Id);
            var aSorted = expected.OrderBy(a => ((User)a).Id);

            Assert.Over.Pairs(aSorted, eSorted, Assert.AreEqual);
        }

        /// 
        /// Tests that all the media in the database is returned
        /// 
        [Test]
        public void WhenAskingForTheMediaAllTheContentsShouldBeReturned()
        {
            var expected = factory.LotsOf<IMediaElement>();

            var actual = this.mediaLib.Contents;

            Assert.IsNotNull(actual, "The users should not be null");
            
            var eSorted = expected.OrderBy(e => ((MediaElement)e).Id);
            var aSorted = expected.OrderBy(a => ((MediaElement)a).Id);

            Assert.Over.Pairs( aSorted, eSorted, Assert.AreEqual );
        }

        /// 
        /// Tests that when adding new media the collection grows
        /// 
        [Test]
        public void WhenAddingNewMediaTheCollectionShouldHaveOneMore()
        {
            var oldContents = this.mediaLib.Contents;

            var oldCount = oldContents.Count();

            var user = factory.OneUser();

            var added = this.mediaLib.AddMedia<IMovieElement>( "Test", user );

            var actualContents = this.mediaLib.Contents;

            Assert.IsNotNull( added );
            Assert.AreEqual( oldCount + 1 , actualContents.Count(), "The count should be increased by one");
            Assert.AreEqual( added, actualContents.Last() );
        }
To generate another test we just need to write a new class and inherit from BaseDbTest. To download the full example please click here DbTest source code. Enjoy.