Home > Uncategorized > validating-object-mothers

validating-object-mothers

October 24th, 2010 Leave a comment Go to comments

I was in a pairing session and we decided that that this syntax described here is way too noisy:

new Banner { Name="" }.SetupWithDefaultValuesFrom(ValidMO.Banner).IsValid().ShouldBeFalse()

So we rewrote it using anonymous objects which made it nicer to read:

a.Banner.isValid().with(new { Name="john" })

A couple of notes on this style:

  • I am using the style of lowercase for test helpers. As per above a, isValid and with.
  • I am using nested classes to create a DSL feel: eg as@a@._object_ replaces the idea of ValidOM._object_
  • I am wrapping multiple assertions in isValid and isInvalid (they are wrappers that call the domain object IsValid and provide assertions – these assertions can be overwritten for different test frameworks which at this stage is MSTest)

Unit test object builder

This code has two tests: Valid and InvalidHasNoName. The first test checks that I have setup (and maintained) the canonical model correctly and that it behaves well with the validator. The second test demonstrates testing invalid by exception. Here there rule is that the banner is invalid if it has no name.

  using Domain.Model;
  using Microsoft.VisualStudio.TestTools.UnitTesting;

  namespace UnitTests.Domain.Model
  {
      [TestClass]
      public class BannerPropertyValidationTest
      {
          [TestMethod]
          public void Valid()
          {
              a.Banner.isValid();
          }

          [TestMethod]
          public void InvalidHasNoName()
          {
              a.Banner.isInvalid().with(new {Name = ""});
          }
      } 
  }

Here’s the canonical form that gives us the object as a.Banner:

  namespace UnitTests.Domain
  {
      public static class a
      {
          public static Banner Banner
          {
              get  { return new Banner  { Name = "Saver" }; }
          }
      }
  }

At this stage, you should have a reasonable grasp of the object through the tests and what we think is exemplar scenario data. Here’s the model with validations. I won’t show but there is an extension methods

  using Castle.Components.Validator;

  namespace Domain.Model
  {
      public class Banner
      {
        [ValidateNonEmpty]
        public virtual string Name { get; set; }
      }
  }

Builder extensions: with

Now for the extensions that hold this code together. It is a simple piece of code that takes the model and anonymous class and merges them. As a side note I originally thought that I would use LinFu to do this but it can’t duck type against concrete classes, only interfaces. And I don’t have interfaces on a domain model.

	using System;

	namespace Domain
	{
	    public static class BuilderExtensions
	    {
	        public static T with<T>(this T model, object anon) where T : class
	        {
	            foreach (var anonProp in anon.GetType().GetProperties())
	            {
	                var modelProp = model.GetType().GetProperty(anonProp.Name);
	                if (modelProp != null)
	                {
	                    modelProp.SetValue(model, anonProp.GetValue(anon, null), null);
	                }
	            }
	            return model;
	        }
	    }
	}

So if you want to understand how the different scenarios it works on, here’s the tests:

	using Domain;
	using Domain.Model;
	using Microsoft.VisualStudio.TestTools.UnitTesting;

	namespace Tests.Unit
	{
	    [TestClass]
	    public class WithTest
	    {
	        [TestMethod]
	        public void UpdateBannerWithName_ChangesName()
	        {
	            var a = new Banner { Name = "john" };
	            var b = a.with(new { Name = "12345" });
	            Assert.AreEqual(b.Name, "12345");
	        }

	        [TestMethod]
	        public void UpdateBannerWithEmptyName_ChangesName()
	        {
	            var a = new Banner { Name = "john" };
	            var b = a.with(new { Name = "" });
	            Assert.AreEqual(b.Name, "");
	        }

	        [TestMethod]
	        public void UpdateBannerWithEmptyName_ChangesNameAsRef()
	        {
	            var a = new Banner { Name = "john" };
	            a.with(new { Name = "" });
	            Assert.AreEqual(a.Name, "");
	        }

	        [TestMethod]
	        public void UpdateBannerChainedWith_ChangesNameAndDescriptionAsRef()
	        {
	            var a = new Banner { Name = "john" };
	            a.with(new { Name = "" }).with(new { Description = "hi" });
	            Assert.AreEqual(a.Name, "");
	            Assert.AreEqual(a.Description, "hi");
	        }

	        [TestMethod]
	        public void UpdateBannerWithName_ChangesNameOnly()
	        {
	            var a = new Banner { Name = "john", Description = "ab" };
	            var b = a.with(new { Name = "12345" });
	            Assert.AreEqual(b.Name, "12345");
	            Assert.AreEqual(b.Description, "ab");
	        }

	        [TestMethod]
	        public void UpdateBannerWithPropertyDoesntExist_IsIgnored()
	        {
	            var a = new Banner { Name = "john" };
	            var b = a.with(new { John = "12345" });
	            // nothing happens!
	        }
	    }
	}

Builder extensions: validators

Now that we have the builder in place, we want to be able to do assertions on the new values in the object. Here’s what we are looking for a.Banner.isValid().with(new{Name="john"}). The complexity here is that we want to write the isValid or isInvalid before the with. We felt that it read better. This adds a little complexity to the code – but not much.

The general structure below goes something like this:

  1. add an extension method for the isValid on a domain object
  2. that helper returns a ValidationContext in the form of a concrete Validator with a test assertion
  3. we need to create another with on a ValidationContext to run the Validator
  4. Finally, in the with we chain the with with the anonymous class and do the assert
	using Domain;
	using Domain.Model;
	using Microsoft.VisualStudio.TestTools.UnitTesting;

	namespace Tests.Unit
	{
	    public static class ValidationContextExtensions
	    {
	        public static ValidationContext<T> isInvalid<T>(this T model)
	        {
	            return new Validator<T>(model, (a) => Assert.IsFalse(a));
	        }

	        public static ValidationContext<T> isValid<T>(this T model)
	        {
	            return new Validator<T>(model, (a) => Assert.IsTrue(a));
	        }

	        public static T with<T>(this ValidationContext<T> model, object exceptions) where T : class
	        {
	            model.Test.with(exceptions);
	            model.Assert(model.Test.IsValid());
	            return model.Test;
	        }
	    }

	    public interface ValidationContext<T>
	    {
	        T Test { get;  set; }
	        Action<bool> Assertion { get;  set; }
	        void Assert(bool isValid);
	    }

	    public class Validator<T> : ValidationContext<T>
	    {
	        public Validator(T test, Action<bool> assertion) {
	            Test = test;
	            Assertion = assertion;
	        }
	        public T Test { get; set; }
	        public virtual Action<bool> Assertion { get; set; }
	        public void Assert(bool value)
	        {
	            Assertion.Invoke(value);
	        }
	    }
	}

Just a last comment about the interface and implementation. I have gone for naming the interface differently to the interface (ie not IValidator) because I want to avoid using the I@ convention and see where it takes me. In this case, the @with needs to be able to chain itself to something – to me this is the validation context. This context then has a validator in it (eg valid/invalid). In this case the interface isn’t merely a contract it is actually being used concretely itself without an implementation. In fact, we could almost have the interface living without its properties and methods definitions at this stage, or perhaps the interface could have become an abstract class – either solution would entail less code (but slightly weird conventions).

Righto, a bit more showing of tests last:

	using Domain.Model;
	using Microsoft.VisualStudio.TestTools.UnitTesting;

	namespace Tests.Unit
	{

	    [TestClass]
	    public class ValidationContextTest
	    {
	        private const string NameCorrectLength = "johnmore_than_six";
	        private const string NameTooShort = "john";

	        [TestMethod]
	        public void UpdateBannerWithInvalidExtensionOnWith()
	        {
	            var a = new Banner { Name = NameTooShort };
	            a.isInvalid().with(new { Name = "" });
	        }

	        [TestMethod]
	        public void UpdateBannerWithValidExtensionOnWith()
	        {
	            var a = new Banner { Name = NameTooShort };
	            a.isValid().with(new { Name = NameCorrectLength });
	        }

	        [TestMethod]
	        public void NewBannerIsValidWithoutUsingWith()
	        {
	            var a = new Banner { Name = NameTooShort };
	            a.isValid();
	        }

	        [TestMethod]
	        public void NewBannerIsInvalidWithoutUsingWith()
	        {
	            var a = new Banner { Name = NameCorrectLength };
	            a.isInvalid();
	        }
	    }
	}

Just a final bit, if you are wondering between IsValid with caps and isValid. Here’s validator running code on the domain model that we are wrapping in our validators.

	using Castle.Components.Validator;

	namespace Domain.Model
	{
	    public static class ValidationExtension
	    {
	        private static readonly CachedValidationRegistry Registry = new CachedValidationRegistry();

	        public static bool IsValid<T>(this T model) where T : class 
	        {
	            return new ValidatorRunner(Registry).IsValid(model);
	        }
	    }
	}

I hope that helps.

  1. December 7th, 2010 at 13:12 | #1

    In Ruby, the popular library for something like “object mothers” is FactoryGirl: https://github.com/thoughtbot/factory_girl

    I’ve been using a C# port that I wrote called FactoryMan: https://github.com/remi/FactoryMan

    You’d probably dig it. I’m not saying use it – you got your own thing going and my library is pretty green too. But it’s another library attempting to solve the same problem.

    Here’s an example of what my model specs look like: https://gist.github.com/57d57b714625a5b6d787#file_model_spec_snippet.cs

    In that example, “f” is just a reference to an object that I put properties on for each of my factories. How you organize your factories isn’t something that’s currently built into FactoryMan … you can roll however you like.

    Also note that the example uses NUnit … I’m trying to find a BDD solution that I like at the moment. I’m used to RSpec so I’ve been trying out MSpec and, generally, I like it. NBehave is definitely on the list of things to checkout.

  2. todd
    December 7th, 2010 at 17:54 | #2

    Remi,

    Thanks. Nice port. I am just keen to keep the factory methods as silent as possible and hence why I have ended up down the generics/static methods line.

    I noticed that I hadn’t updated my post that there is another builder written by Nat Pyrce with a dotnet port called make it easy: http://code.google.com/p/make-it-easy/. I saw it and then realised that the syntax was almost identical!

    todd

  1. December 5th, 2010 at 10:17 | #1