Castle demo app: ActiveRecord basics and unit testing

Castle project is a great .NET enterprise application framework. It helps us develop .NET applications and web sites by providing the plumbing and making it easy to test the most important parts of the system. I’ve decided to build a demo application with the Castle project for an internal training session, to show how easy it is to work with this framework and to demonstrate the best practices. I will post the tutorial in parts on this web site as I develop it. In the first post, we work on the object-relational mapping with ActiveRecord and write unit tests for the database mapping layer.

Here is the stuff that you’ll need to run these examples:

Introducing EvilLink

We’ll build an online bookmarking application, called it EvilLink. Here are the user stories that we will develop:

  1. As a site owner, I want users to register and leave their e-mail address so that I can spam them later (hence the app name).
  2. As a user, I want to record my web links online, so that I can access them from anywhere.
  3. As a user, I want to review the links that I previously recorded so that I can visit the interesting sites.
  4. As a user, I want to edit details and descriptions of the links that I previously recorded, so that I can keep them up to date.


This will be a rather simplistic web application, but it will allow us to try out the most important features of all three main components of the Castle project: the ActiveRecord object-relational mapping tool, the Monorail web model-view-controller framework and the Windsor dependency injection container. We will develop this application with full test support, meaning that our goal is to cover everything below the UI surface with unit tests.

Story 1: User registration

To implement this story, we’ll create a User object, connect it to the database, make sure that the ORM system works, and then build a simple Web site on top of that. During this exercise, we show how straightforward it is to use ActiveRecord. In the next one, we work on the basic layout of a Monorail web site and show the way that controllers handle incoming requests to complete the first user story.

The User object

Let’s first create the User class and related database mappings. Create a new solution for this project in Visual Studio, and open a new project called EvilLink.Database. We’ll put database-related objects there.

ActiveRecord is a software architectural pattern that maps objects directly to table rows, and object properties to table columns. This pattern combines domain logic and data, providing easy persistence but not a very nice separation of responsibilities. For more information on this pattern, see Martin Fowler’s Patterns of Enterprise Application Architecture page.

Under the hood, Castle’s ActiveRecord uses NHibernate, but with almost no configuration. In general, preferring convention over configuration is one of the best things about the Castle framework. Instead of an external mapping file, ActiveRecord requires that we put a few attributes on the class. For start, the entire class should be marked with [ActiveRecord]. Persistent properties should be marked as [Property], and the class must have a numeric primary identifier, marked as [PrimaryKey]. Although it can work on plain CLR classes (the only requirement is a default public constructor without arguments), ActiveRecord also has a few utility base classes that you can extend. ActiveRecordBase supplies a bunch of useful finders and actions. ActiveRecordValidationBase integrates with the Castle component validator framework, and provides instant validation features. That means that you can annotate your properties with validation rules, and the object itself will refuse to save or update the database if it is invalid. It also gives you nice validation error messages if the object is not valid, ready to be displayed to the end users. Standard validators include checking whether an attribute is unique, not empty, formatted like an e-mail and a number of other similar actions. For a full list, see the Castle Components Validator documentation. If you make a mistake in the attribute annotations, you will not get a compilation error. Problems like that don’t even pop up when the classes are loaded, but come up when you try to use the class with a misleading message like “ActiveRecordStarter.initialise call was not executed with the type”. Remember to double-check the public constructor and class and property annotations if you get that exception.

We’ll use this to validate that the username is unique, that the e-mail is in the correct format and that the user’s name is not empty.

All ActiveRecord attributes are in the Castle.ActiveRecord namespace. Validation attributes are in the Castle.Components.Validator namespace. Add references to Castle.Core.dll, Castle.ActiveRecord.dll and Castle.Components.Validator.dll and create the User class:

using System;
using Castle.ActiveRecord;
using Castle.Components.Validator;
namespace EvilLink.Database
{
    [ActiveRecord]
    publicclass User : ActiveRecordValidationBase<User>
    {
        private int id;
        private String username;
        private String password;
        private String email;
        private String name;
 
        public User()
        {
        }
        public User(string name, string username, string password, string email)
        {
            this.username = username;
            this.password = password;
            this.email = email;
            this.name = name;
        }
 
        [PrimaryKey]
        public int Id
        {
            get { return id; }
            set { id = value; }
        }
        [Property]
        [ValidateIsUnique]
        public string Username
        {
            get { return username; }
            set { username = value; }
        }
        [Property]
        [ValidateNonEmpty]
        public string Name
        {
            get { return name; }
            set { name= value; }
        }
        [Property]
        [ValidateNonEmpty]
        public string Password
        {
            get { return password; }
            set { password = value; }
        }
        [Property]
        [ValidateEmail]
        public string Email
        {
            get { return email; }
            set { email = value; }
        }
        public override bool Equals(object obj)
        {
            User us=obj as User;
            if (us == null) return false;
            return us.id == this.id;
        }
        public override int GetHashCode()
        {
            return id.GetHashCode();
        }
        public override string ToString()
        {
            return "Userid=" + id;
        }
    }
}

And that’s more or less everything about the database mapping. ActiveRecord will create all the SQL commands automatically. It can even create the database schema. The only thing left is to point it to the correct database.

Step 2: Verifying that the model works

To verify that our new User object works correctly, let’s write a unit test (of course, some purists will now note that I should be writing unit tests before the production code, but it’s a bit hard to explain things in that order. In any case, the User class is fairly simple and contains no business logic, so it is not such a sin to write the unit test after the class. When we build in more business logic later, we’ll do it properly).

Let’s create a new project for database tests, and call it EvilLink.Database.Test. Add references to the three Castle libraries as in the Database project, then also add a reference to the EvilLink.Database project and to NUnit.Framework.dll and NHibernate.dll (you’ll find them in the dependencies zip file in the Castle release).

To connect the User class to the database, we need to initialise ActiveRecord framework by telling it the database configuration. Castle.ActiveRecord.ActiveRecordStarter class is used for that. We need to call the Initialise method and pass the configuration file and list of record classes. We can load the configuration from an Application.Config file or from an external file. Because we want to run this inside the NUnit test runner, let’s use an external file. Theoretically, we can send a list of record classes to the ActiveRecordStarter, but we can also supply the whole assembly and let it find all relevant classes itself. Here are the two lines that prepare our ORM layer:

IConfigurationSourcesource = new XmlConfigurationSource(
  "ActiveRecordConfig.xml");
ActiveRecordStarter.Initialize(Assembly.GetAssembly(
  typeof(EvilLink.Database.User)), source);

Having a dedicated assembly for record classes will make it easier to load and initialise the records appropriately. Avoid putting a lot of non-record classes in such assemblies, because ActiveRecordStarter will have to analyse all the classes in the assembly.

ActiveRecordStarter contains a bunch of other useful methods, most importantly CreateSchema and DropSchema that will try to create or delete the relevant database objects. I emphasised try because there are some interesting bugs in this that prevent correct initialisation of many-to-many mappings in SQL Server. For now, we’ll use this functionality. Later on, if you find that it starts causing you problems, create the schema yourself. ActiveRecordStarter normally allows you to initialise it only once during an application. For unit tests, we want to drop and recreate the schema before every test to avoid dependencies, so we’ll need to tell it to ignore this security check by calling ResetInitializationFlag.

As most ORM tools, ActiveRecord uses the concept of session scopes to reduce database communication and ensure data consistency. All operations on record objects should be performed within a session scope, and the changes are persisted in the database when the session is flushed or the scope ends. In the context of unit tests, it makes sense to automatically create a scope before tests and discard the scope after tests. To verify persistence functionality, we can flush the session and try to load the objects from the database.

To make testing easier, let’s create a utility class that will take care of all ActiveRecord initialisation and session control. It will also provide a method to flush the session so that we can test persistence. Add this class to the EvilLink.Database.Test project:

using System;
using NUnit.Framework;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework;
using Castle.ActiveRecord.Framework.Config;
using System.Reflection;
namespace EvilLink.Database.Test
{
    // not a test fixture, it should not be invoked directly
    public abstract class ARTestBase
    {
        protected SessionScope scope;
 
        [TestFixtureSetUp]
        public void InitialiseAR()
        {
            ActiveRecordStarter.ResetInitializationFlag();
            IConfigurationSource source = new 
              XmlConfigurationSource("ActiveRecordConfig.xml");
            ActiveRecordStarter.Initialize(
               Assembly.GetAssembly(typeof(EvilLink.Database.User)),
              source);
        }
        [SetUp]
        public virtual void SetUp()
        {
            ActiveRecordStarter.DropSchema();
            ActiveRecordStarter.CreateSchema();
            scope = new SessionScope();
        }
        [TearDown]
        public virtual void TearDown()
        {
            scope.Dispose();
        }
        public void Flush()
        {
            scope.Flush();
            scope.Dispose();
            scope = new SessionScope();
        }
       
    }
}

We now need to supply the database configuration to ActiveRecord. Create a file called ActiveRecordConfig.xml in the project, and use this as a template:

<?xml version="1.0" encoding="utf-8" ?>
<activerecord isWeb="false" pluralizeTableNames="true"> 
<config>
      <add key="hibernate.connection.driver_class"
              value="NHibernate.Driver.SqlClientDriver" />
      <add key="hibernate.dialect"
              value="NHibernate.Dialect.MsSql2005Dialect" />
      <add key="hibernate.connection.provider"
              value="NHibernate.Connection.DriverConnectionProvider" />
      <add key="hibernate.connection.connection_string"
              value="Data Source=.\SQLEXPRESS;Initial Catalog=castletest;
user id=castletest;password=castletest" />
</config>
</activerecord>

This example connects to a SQLExpress database on the local machine (.\SQLEXPRESS) under the credentials of user castletest with the password castletest, and selects castletest as the starting database. So either create that on your local instance, or enter different connection details in the connection_string property. To use a different type of database, see the ActiveRecord configuration reference. Just remember to keep isWeb=”false” pluralizeTableNames=”true” in the activerecord element. The first attribute tells ActiveRecord not to use automatic thread/transaction management and the other makes sure that the User objects are saved in the users table (otherwise you will get an error because User is a keyword in SQL Server). Right click on the file, select properties, and then choose “Copy always” as the “Copy to Output Directory” option to make sure that this configuration file is available at runtime when we need it.

Now, let’s write the unit test. Create a UserTests class and check whether we can register a user and whether the validations work correctly:

using System;
using NUnit.Framework; 
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework;
using Castle.ActiveRecord.Framework.Config;
 
namespace EvilLink.Database.Test
{
    [TestFixture]
    public class UserTests : ARTestBase
    {
        [Test]
        public void TestInvalidFormatEmail()
        {
            User u = new User("Mike Smith", "mike", "mpass123", "mike-mike.com");
            Assert.IsFalse(u.IsValid());
            try
            {
                u.Save();
                Assert.IsFalse(true, "invalid password object saved");
            }
            catch (Exception)
            { 
            }
        }
        [Test]
        public void TestNonUniqueUsername()
        {
            User u = new User("Mike Smith", "mike", "mpass123", "mike@mike.com");
            u.Save();
            Flush();
            u = new User("Tom Smith", "mike", "tpass123", "tom@mike.com");
            Assert.IsFalse(u.IsValid());
            try
            {
                u.Save();
                Assert.IsFalse(true, "duplicate username object saved");
            }
            catch (Exception)
            {
            }
        }
        [Test]
        public void TestAddingUsers()
        {
            User u = new User("Mike Smith", "mike", "mpass123", "mike@mike.com");
            u.Save();
            Flush();
            User[] fromDb = User.FindAllByProperty("Username", "mike");
            Assert.AreEqual(1, fromDb.Length);
            Assert.AreEqual("mike@mike.com", fromDb[0].Email);
        }
    }
}

Compile the solution, and run the test with NUnit. It should confirm that the database mapping works correctly.

You can also check the database directly, Mike should be there:

You can download the source code for this example from http://gojko.net/resources/EvilLink_i1.zip

Key stuff to remember:

  • the record class needs to be annotated with the [ActiveRecord] attribute, be public, have a no-parameter public constructor. Otherwise loading fails, but you don’t get an error at that point — you will get an error later mentioning how ActiveRecordStarter.initialise call was not executed with the type. This can be a bit misleading.
  • you need to initialise ActiveRecord and load types or whole assemblies. The best practice is to create an assembly especially for ActiveRecord types and then load that.
  • beware of using DB table/field names that are keywords (for example User in SQL Server 2005); converting table names to plurals helps to avoid some problems, but still beware that such problems can happen.
  • make sure you use ActiveRecordValidationBase if you want validations to work. Having only validation attributes on the properties is not enough.
  • Kill the initialisation flag in unit tests to allow re-initialisation
  • ActiveRecord can generate the schema for you — this is very helpful during initial stages of the project but it may not always work as expected.

Next exercise

In the next part of this tutorial, we complete the first user story by developing a web page that allows people to register. I will post the next part on this web site shortly. You can subscribe to RSS updates to get a notification when the next part is online. If you are in UK, and want to learn more about the Castle project, drop by Skills Matter on the 15th of May for a two-hour workshop on Agile Web development with Castle. We are going for beers after the talk.

I'm Gojko Adzic, author of Impact Mapping and Specification by Example. I'm currently working on 50 Quick Ideas to Improve Your User Stories. To learn about discounts on my books, conferences and workshops, sign up for Impact or follow me on Twitter. Join me at these conferences and workshops:

Specification by Example Workshops

Product Owner Survival Camp

Conference talks and workshops

25 thoughts on “Castle demo app: ActiveRecord basics and unit testing

  1. While I agree that you should try and avoid naming objects the same as SQL keywords, you may be integrating with a legacy DB and have no choice. In those cases, you can tell ActiveRecord what to use as the table name and enclose it in brackets so you’ll get valid SQL. In your example:

    [ActiveRecord("[User]“)]
    public class User : ActiveRecordValidationBase

  2. Hi Adam,

    I’m using an empty catch to ignore an expected exception during a test. The AssertFalse(true) statement after the operation inside the try block is used to fail the test if the exception does not happen. Is there a better way to do it?

  3. You should use the ExpectedException attribute on your test to verify that the exception was thrown, the test will fail if the exception isn’t thrown.

    e.g.
    [ExpectedException(typeof(FileNotFoundException))]

  4. Instead of :
    Assert.IsFalse(true, “duplicate username object saved”);

    Can I suggest:
    Assert.Fail(“duplicate username object saved”);

  5. >>You should use the ExpectedException attribute on your test to verify that the exception was thrown, the test will fail if the exception isn’t thrown.<<<

    Generally, no you shouldn’t … ExpectedException is generally considered “a bad thing” these days, as it does not identify where the exception occured, and can therefore give misleading results. The try/catch/fail is far more precise.

    Even NUnit has now moved to Assert.Throws() instead of ExpectedException

  6. An example from my current project …

    [Test]
    public void Handler_denys_access_with_unauthenticated_user()
    {
    try
    {
    var request = new DemandAuthorisationRequest {User = string.Empty, DemandFor = “CanAdd”};
    handlerUnderTest.Handle(request);
    }
    catch(SecurityException)
    {
    return;
    }
    Assert.Fail(“Access was allowed to unathenticated user”);
    }

  7. I had the same question about the ExceptionExpected. Thanks Casey for pointing out an alternative. Just curious though, why is the ExceptionExpected considered a bad practice if that is what you ARE expecting is an exception?

  8. use “does user exist” mechanism instead of introducing exception handling for your expected behavior

  9. @adam
    that would be fine if we were checking if the user exists. In this case, the test is about whether activerecord is going to prevent someone from saving an invalid user. How would you test that without actually invoking the exception?

  10. you would not call user.save until you queried for one by email, in this case. You would not rely on your repository to handle your BL by throwing an “exists” exception.

  11. Adam,
    Sorry, I really do not understand the difference between your suggestion and what I implemented in the unit test. I have checked for IsValid before trying the exception, but I still want to validate that the framework will prevent people that do not check for duplicates from saving the user.

  12. This is one level above, that’s the difference. I wouldn’t rely on my repository’s exception generation implement my BL.

    with NHQG help to get rid of criteria syntax, here’s the pseudo code

    if (null!=User.Find(userid == potentialId && email==potentialEmail)) (new User(name, potentialId, “mpass123″, potentialEmail)).Save();
    else //display user already exists

  13. Hi,

    I’m wondering if it is possible to execute my tests without hitting the database. For example, I want to create an entity and verify that my model class fetches (or ignores) it. Or I want to execute a method and verify that an entity object has been created, without a database roundtrip. Hitting a database may be fine when you do integration testing, but I don’t want to touch it in _every_ test. If you can suggest another pattern, I’ll be happy to try it.

    Another useful application is when you are pretty sure that you have all relevant objects fetched already and you don’t want to fetch them again.

    I know that ISession is some sot of a cache, but the online documentation on AR cache is “to be added”. Could you please pint me in the right direction?

    Thanks
    ulu

  14. Hi Ulu,

    ActiveRecord mixes domain logic and storage — so it is not the best choice for more complex applications. You can use NHibernate directly from Castle and use the Repository pattern, for example, to write the code in a way that enables you to test domain code independently of storage.

  15. Hi,

    I think the text in your TestInvalidFormatEmail() is wrong. It says “password”when it’s checking for email.

    Thanks,

    Federico

  16. I’m trying to follow this tutorial, but having problems. (I’m calling “User” “Client”, but otherwise I’m pretty much the same as the examples given.)

    Here’s the error I get when I try to run NUnit for the first time:

    Scrumpy.Database.Test.Tests.ClientTests.TestAddingUsers:
    Castle.ActiveRecord.Framework.ActiveRecordException : Could not drop the schema
    —-> NHibernate.ADOException : Could not close Npgsql.NpgsqlConnection connection
    —-> System.NotSupportedException : This stream does not support seek operations.
    TearDown : System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
    —-> System.NullReferenceException : Object reference not set to an instance of an object.

  17. Hi Stew,

    This error message suggests that your schema cannot be dropped as part of the unit test fixture set-up. Maybe some data consistency constraints are preventing you from dropping the client table (eg you have more tables in the schema, but you only loaded the Client table into AR during unit testing). Try to drop all tables in the schema manually before running the test.

  18. Thanks for taking the time to respond.

    I’m still stuck here. There is no client schema in the database right now. Here’s what the error looks like right now:

    Scrumpy.Database.Test.Tests.ClientTests.TestNonUniqueUsername:
    Castle.ActiveRecord.Framework.ActiveRecordException : Could not perform Save for Client
    —-> NHibernate.ADOException : cannot close connection
    —-> NHibernate.ADOException : Could not close Npgsql.NpgsqlConnection connection
    —-> System.NotSupportedException : This stream does not support seek operations.
    TearDown : System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
    —-> NHibernate.ADOException : cannot close connection
    —-> NHibernate.ADOException : Could not close Npgsql.NpgsqlConnection connection
    —-> System.NotSupportedException : This stream does not support seek operations.

    All suggestions appreciated. I’m very stuck.

  19. I upgraded to the latest Npgsql and that seems to have broken the ice. I think I’m OK now.

    Thanks again for the help.

  20. Just in case anyone else has this problem. If you are using the latest castle bits, you’ll need to update your config section by removing all the “hibernate.”

    So you’ll have these properties
    key=”connection.driver_class”
    key=”dialect”
    key=”connection.provider”
    key=”connection.connection_string”

    Wasted 2 hours on that lol ;)

  21. In case anyone else had the following problem, add NHibernate.ByteCode.Castle dll to your test project references and then the factoryclass value:

    Error:
    NHibernate.Bytecode.ProxyFactoryFactoryNotConfiguredException : The ProxyFactoryFactory was not configured

    Amended Config:

  22. Pingback: Better Testing With Castle:ActiveRecord « Code Zombie

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>