Castle ActiveRecord: ValidateIsUnique Vs. Testing
In my Castle ActiveRecord project, I want to use the ValidateIsUnique attribute, but that means when testing my models I have to have bring up the entire database and initialize Castle ActiveRecord etc. even when I’m not testing my persistence layer which is slow and undesirable. I’m using ActiveRecordMediator based repositories. It really mucks up testability.
Perhaps this is just an indicator that “ValidateIsUnique” maybe doesn’t belong in my domain models? It’s a database concern I guess, but it’s terribly convenient to be able to have it there and get the error message when I’m doing form submission from MonoRail.
So, after posting to the Castle Project Users Group, and getting help from Eric Hauser and Victor Kornov on the issue, and came up with this:
/// <summary> /// Validate that the property's value is unique in the database when saved. /// /// Also supports being disabled (primarily for testing purposes). /// </summary> [Serializable, CLSCompliant(false)] public class ValidateIsUniqueSometimesAttribute : AbstractValidationAttribute { private static bool enabled = true; /// <summary> /// When set to true (the default value), the Validator will run as expected. /// Otherwise the validator is disabled. /// /// /// </summary> public static bool Enabled { get { return enabled; } set { enabled = value; } } /// <summary> /// Initializes a new instance of the <see cref="ValidateIsUniqueSometimesAttribute"/> class. /// </summary> public ValidateIsUniqueSometimesAttribute() : base() { } /// <summary> /// Initializes a new instance of the <see cref="ValidateIsUniqueSometimesAttribute"/> class. /// </summary> /// <param name="errorMessage">The error message.</param> public ValidateIsUniqueSometimesAttribute(String errorMessage) : base(errorMessage) { } private IValidator GetCorrectValidator() { if (Enabled) { return new IsUniqueValidator(); } return new AlwaysReturnsNoErrorsValidator(); } /// <summary> /// Constructs and configures an <see cref="IValidator"/> /// instance based on the properties set on the attribute instance. /// </summary> /// <returns></returns> public override IValidator Build() { var validator = GetCorrectValidator(); ConfigureValidatorMessage(validator); return validator; } }
I couldn’t do exactly what Eric recommended because the controller property in ValidateIsUniqueAttribute is private, so I couldn’t set it. I guess I could have gone all reflect-y on it, but that’s so rarely a good idea. So I ended up with a bunch of copy paste from ValidateIsUniqueAttribute, and I’m ok with that.
So to use it, at the beginning of the [SetUp] method in my unit tests, I just have to call ValidateIsUniqueSometimes.Enabled = false.
Yes, it’s a hack. Yes, it’s kinda gross, but it works, and I only need to use it when testing the validation logic of my Domain Models.
Oh and speaking of validation, Eric just put some really bad-ass new validation stuff into the Castle trunk. Now I have to pull castle trunk again. Grrr, damn you Castle for being so awesome.
Skidoosh!
Post a Comment