Improving tests with Extension Methods

In my constant search for making it easier to write tests for common things in our framework, I believe I was able to clear some things up by using extension methods. Not that this hasn’t been done before, it’s just that I want to document how I got to it so that I can use this post to explain the approach to other people (and maybe help somebody else learning about this).  🙂

The scenario is: we need some clean and easy way to test validity of entities after business rules have been evaluated. One approach would be to write the test like so:

[TestMethod] public void SomeTest() { CustomerEntity entity = new CustomerEntity(); bool entityViolatesRule = false;
// make the checks and assign true/false to the entityViolatesRule variable
Assert.IsTrue(entityViolatesRule, "Some assertion message..."); }

Disclaimer: nope, I don’t name my tests like that. It’s just that the test name isn’t important here!

The test would need whatever logic necessary for checking whether the entity violates a given rule, and then call an assertion for it.

In order to clean that up a little bit, I created a Violates extension method on my Entity class. The extension is only meant to be used by tests. The method takes in a RuleViolationExpectation object, meant to carry the expectations for the violation of a specific rule. An assertion would be called from within that method:

public static class EntityTestExtensions { public static void Violates(this Entity entity, RuleViolationExpectation expectation) { bool entityViolatesRule = false;
// some code that looks at the expectation and checks
// whether the entity meets the expectation... Assert.IsTrue(entityViolatesRule, "Some assertion message..."); } }

 
The RuleViolationExpectation class looks like this:
 
public class RuleViolationExpectation
{
    public Entity Entity { get; set; }
    public Type RuleType { get; set; }
    public string Message { get; set; }
    public ViolationLevel Level { get; set; }
}

The test could now look like this:

[TestMethod]
public void SomeTest()
{
    CustomerEntity entity = new CustomerEntity();

    entity.Violates(new RuleViolationExpectation 
                    { 
                        RuleType = typeof(CustomerNameIsValidRule), 
                        Level = ViolationLevel.Violation, 
                        Message = "Customer name must..." 
                    });
}

I liked that better because I got rid of the Assert, as well as any logic that checks whether the entity violates the rule according to the expectation. Now all the developer has to do is to call the Violates method on the entity, passing in the expectation, and the framework does the rest (verification and assertion).

One thing bothered me, though: the call to the method read sort of funny, kind of like "entity violatates rule violation expectation…". That didn’t really express the intent well: it’s not that the "entity violates a rule violation expectation"…. it’s more like the "entity should violate a specific rule according to the given expectation".

I then rewrote the test based on how I’d like it to read for better comprehension:

[TestMethod]
public void SomeTest()
{
    CustomerEntity entity = new CustomerEntity();

    entity.Violates<CustomerNameIsValidRule>()
          .WithMessage("Customer name must blah blah blah...")
          .OnLevel(ViolationLevel.Violation)
          .Verify();
}

I thought that read much better. It’s more like "entity violates the CustomerNameIsValid rule, with a message like ‘Customer name must blah blah blah…’, and on level Violation, so Verify all of that for me". For the records, the other level option is Warning.

Notice that from the call to Violates on, that’s really just a long chained method call, split up into several lines just to make the code easier to read, without requiring horizontal scrolling.

In order to enable such syntax, I’ve added one more extension method to my EntityTestExtensions class:

public static RuleViolationExpectation Violates<TRule>(this Entity entity)
    where TRule : Rule
{
    RuleViolationExpectation expectation = new RuleViolationExpectation();
    expectation.Entity = entity;
    expectation.RuleType = typeof(TRule);
    return expectation;
}

The method takes the expected rule type as a generic type, instantiates the RuleViolationExpectationViolation class, associates the expectation with the entity, assigns the type of rule to the expectation, and returns it.

Next, I created a RuleViolationExpectationExtensions class, and added extension methods to it, like so:

public static class RuleViolationExpectationExtensions
{
    public static RuleViolationExpectation WithMessage(this RuleViolationExpectation expectation, 
                                                       string message) { expectation.Message = message; return expectation; } public static RuleViolationExpectation OnLevel(this RuleViolationExpectation expectation,
                                                   ViolationLevel level) { expectation.Level = level; return expectation; } public static void Verify(this RuleViolationExpectation expectation) { expectation.Entity.Violates(expectation); } }

Each method extends the RuleViolationExpectation class, and takes in the value for one of the properties we need to assign on the expectation, we assign it, and then returns the expectation back to the caller. Got it? It’s just a bunch of methods acting upon the same object.

The Verify method is the one that works a period (".") at the end of the sentence, by telling the framework we’re done setting up the expectation, and it’s time to verify the entity against the expectation. The method just leverages the Violates method that we already have on the entity; the one that takes in the RuleViolationExpectation object.

The actual implementation I’ve done for this in our framework is more complex and complete; the expectation class has a couple more properties that we need to check for, and it also has logic that validates the expectation so to make sure the developer has provided everything the framework needs in order to verify the entity against the expectation. If there’s piece missing, the framework call an assertion and tells the developer what’s missing.

Also, I’ve created a CodeRush template that makes it REALLY easy for developer to write the code and not miss any piece. The way it works is: I put the name of my entity variable into the clipboard and then type rve (Rule Violation Expectation, but I’ll probably change this), and I get this:

clip_image001

All the developer then needs to do is to fill in the expectations, hitting enter to go through the "fields" (orange highlighted areas) in the code:

clip_image001[7]

Moving along with a test-first approach, I’m already thinking that the developer can write the test first for the rules evaluation verification, and then I’ll write a plug-in that will read the call to "Violates…" and generate the business rule, where the dev then only needs to write the actual business logic. In case the test hasn’t been created first, I can also have a plug-in that’ll look at an existing business rule and then create the test based on it.

I believe such approach has very little friction even for developer who aren’t not entirely comfortable with TDD and test-first. What do you think?

  1. Rails, Cucumber, RSpec, Testing, BDD, and all that stuff « Claudio Lassala's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: