Archives

  • Categories

  • Unit Testing LightSpeed Entities

    If you have not heard of LightSpeed or had a play with it then you should check out the excellent lightweight ORM from the boys at Mindscape.  I have worked with it for a couple of years now and really like it for certain type of projects, I think its simplicity is a good stepping stone for developers making that transition from old data access strategies to ORM technologies.

    The one thing I don’t like about it is that your domain objects are not persistant ignorant of the underlying ORM technology, and have to inherit from an Entity base class.

    I have run into problems when trying to unit test code that use my Lightspeed entities because I cannot just create a new entity without hitting the database.  Normally when you request an entity from the database the construction of that entity is handled by the Lighspeed framework.

    Some of the things that were causing me problems were:

    • I could not assign my own Id for the entity.
    • The Entities throw an exception if they don’t have UnitOfWork set.
    • Could not set up EntityCollection relationships between domain objects as they are read only properties.

    In the end I created a LightSpeedEntityFactory and some helper methods for testing purposes to create my entities and get around some of these issues.  I hope you find the following code useful.

        ///
    
        /// Factory class for building LightSpeedEntity, that are are divorced from a real UnitOfWork.
        /// 
    
        /// To be used for Unit Testing purposes only!
        internal class LightSpeedEntityFactory
        {
            #region Methods
    
            ///
    
            /// Build a LighSpeed Entity with the chosen Id, and a Fake UnitOfWork.
            /// 
    
            /// 
            /// 
            public static T Build<T>(object id) where T : Entity
            {
                var lightSpeedEntity = Build<T>();
    
                lightSpeedEntity.SetId(id);
    
                return lightSpeedEntity;
            }
    
            ///
    
            /// Build a LighSpeed Entity with a Fake UnitOfWork.
            /// 
    
            /// 
            /// 
            public static T Build<T>() where T : Entity
            {
                var lightSpeedEntity = (T)Activator.CreateInstance(typeof (T));
    
                IUnitOfWork unitOfWork = new UnitOfWork();
    
                lightSpeedEntity.SetUnitOfWork(unitOfWork);
    
                return lightSpeedEntity;
            }
    
            #endregion Methods
        }
    
       ///
    
        /// Some helper extension methods for changing the internals of a LightSpeed entity.
        /// 
    
        /// 
        /// We do some very naughty stuff in here using reflection and these methods
        ///  should only be used for the purposes of Unit Testing.
        /// 
        public static class LightSpeedHelper
        {
            #region Methods
    
            ///
    
            /// Set the Id of a LightSpeed Entity. This is usually only a read-accessible property.
            /// 
    
            public static void SetId(this Entity entity, object id)
            {
                var setIdInternalMethod = entity.GetType().GetMethod("SetIdInternal", BindingFlags.NonPublic | BindingFlags.Instance);
    
                setIdInternalMethod.Invoke(entity, new[] {id});
            }
    
            ///
    
            /// Sets a read-only property on a LightSpeed Entity.
            /// For setting up an object for testing purposes only.
            /// 
    
            /// lightspeedEntity.SetProperty(a => a.Addresses).SetValue(addresses)
            /// 
            /// The type of the ESULT.
            /// 
            public static IPropertySetter<RESULT> SetProperty<T, RESULT>(this T entity, Expression<Func<T, RESULT>> action) where T : Entity
            {
                var outerMember = (MemberExpression)action.Body;
    
                var outerProp = (PropertyInfo)outerMember.Member;
    
                var propertyName = outerProp.Name;
    
                IPropertySetter<RESULT> propertySetter = new PropertySetter<RESULT>(entity, propertyName);
    
                return propertySetter;
            }
    
            ///
    
            /// Sets the unit of work on a LighSpeed Entity.
            /// 
    
            public static void SetUnitOfWork(this Entity entity, IUnitOfWork unitOfWork)
            {
                var uowProperty = entity.GetType().GetProperty("UnitOfWork", BindingFlags.NonPublic | BindingFlags.Instance);
    
                uowProperty.SetValue(entity, unitOfWork, null);
            }
    
            #endregion Methods
        }
    
        public class PropertySetter<T> : IPropertySetter<T>
        {
            #region Fields
    
            private readonly object _parent;
            private readonly string _propertyName;
    
            #endregion Fields
    
            #region Constructors
    
            public PropertySetter(object parent, string propertyName)
            {
                _parent = parent;
                _propertyName = propertyName;
            }
    
            #endregion Constructors
    
            #region Methods
    
            public void SetValue(T value)
            {
                var fieldName = FormatPropertyName(_propertyName);
    
                var fieldInfo = _parent.GetType().GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
    
                fieldInfo.SetValue(_parent, value);
            }
    
            private static string FormatPropertyName(string propertyName)
            {
                // get the first letter of the property name.
                var sb = new StringBuilder();
    
                sb.Append("_");
                sb.Append(char.ToLower(propertyName[0]));
                sb.Append(propertyName.Substring(1));
    
                return sb.ToString();
            }
    
            #endregion Methods
        }
    

    UPDATE – ADDED CODE FOR IPROPERTY SETTER THAT WAS MISSING

        public interface IPropertySetter<T>
        {
            #region Methods
    
            void SetValue(T value);
    
            #endregion Methods
        }
    

    6 Responses to “Unit Testing LightSpeed Entities”


    1. LonseLele says:

      Great site this blogs.planbsoftware.co.nz and I am really pleased to see you have what I am actually looking for here and this this post is exactly what I am interested in. I shall be pleased to become a regular visitor :)

    2. Stuart C says:

      Thanks for the kind words. We’re new to blogging so thanks for the words of encouragement.

    3. LnddMiles says:

      Pretty cool post. I just stumbled upon your blog and wanted to say
      that I have really liked reading your blog posts. Anyway
      I’ll be subscribing to your blog and I hope you post again soon!

    4. Ivan L says:

      Hi there,

      It seems you stumbled to the same problem as I did in Unit Testing in a LightSpeed enviroment. I believe your solution will help me greatly yet when I copied the code to VS I cannot seem to find where IPropertySetter is coming from. Is this an interface you declared yourself?

      Sincerely,
      Ivan

    5. Stuart C says:

      Hi Ivan sorry for not replying sooner…I’ve updated the post with the property setter code. Basically it lets you set a public property on a lightspeed entity without a getter by using reflection to set the internal field value.

    6. Owen Swallow says:

      Cool information , THX !

    Leave a Reply