Agile .NET

Ideas & Gotchas

TDD – Create test objects automatically

Posted by Vlad on September 13, 2007


Unit tests normally have three sections: setup, action and validation. In the setup part you often have to create and initialize objects that will be required by the action and that you can use in the validation part to decide whether the code works or not.

The code might look like this:

      [Test]

      public void DoSomethingWorksFine()

      {

            MyObject obj = new MyObject();

            obj.Text = “test text”;

            obj.ID = Guid.NewGuid();

            obj.Date = DateTime.Now;

            // etc.

            testedObject.DoSomething(obj);

            // asserts

      }

Although normally one or two initialized properties are enough, I consider it a good practice to check that all the fields pass well through the test (especially when you’re testing database repositories or web service calls). The problem is that if you use the default values you won’t know if the test passed just because the result has the same initial values.

My solution is a handy utility class that fills the objects properties with random data:

      public static class TestObjectCreator

      {

            static Random rand = new Random();

             public static void FillTestObject(object obj, params string[] excludeProperties)

            {

                  Type objType = obj.GetType();

                  PropertyInfo[] properties = objType.GetProperties();

                  List<string> excludedList = new List<string>(excludeProperties);

                  foreach (PropertyInfo prop in properties)

                  {

                        Object val = GetTestPropertyValue(prop);

                        if (prop.CanWrite && val != null && !excludedList.Contains(prop.Name))

                        {

                              prop.SetValue(obj, val, null);

                        }

                  }

            }

             public static T CreateAndFillTestObject<T>(params string[] excludeProperties) where T: new()

            {

                  T obj = new T();

                  FillTestObject(obj, excludeProperties);

                  return obj;

            }

 

            private static object GetTestPropertyValue(PropertyInfo propInfo)

            {

                  if (propInfo.PropertyType == typeof(System.Int32))

                        return rand.Next(999999);

                  if (propInfo.PropertyType == typeof(System.String))

                        return string.Format(“{0} – {1}”, propInfo.Name, rand.Next(999999));

                  if (propInfo.PropertyType == typeof(System.DateTime))

                        return DateTime.Now.AddDays(rand.Next(200) – 100);

                  if (propInfo.PropertyType == typeof(System.TimeSpan))

                        return TimeSpan.FromMinutes(rand.Next(999999));

                  if (propInfo.PropertyType == typeof(System.Guid))

                        return Guid.NewGuid(); 

                  return null;

            }

      }

It basically has methods to fill an existing object or to create and fill a new one, optionally skipping some properties if it’s necessary. And to use it:

      [Test]

      public void DoSomethingWorksFine()

      {

            MyObject obj = TestObjectCreator.CreateAndFillTestObject<MyObject>();

            testedObject.DoSomething(obj);

            // asserts

      }

2 Responses to “TDD – Create test objects automatically”

  1. [...] TDD – Create test objects automatically [...]

  2. Vivek said

    Hmmmm….

    Only +/- Random(100) for System.DateTime?

    Many subtle ( and not so subtle ) errors would show up if you made that 20000 or something ( Think YnK problems ) where n = [2000, 2036, etc, etc ]

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>