$ cat "

Implementation of a Micro DSL

"

I've previously touch on the topic of using extension methods to clean up the syntax of your unit tests. That approach can give you very expressive and readable tests, for example:

[Test]
public void Validate_RequestWithValidPath_Ok()
{
"GET /valid/path.html HTTP/1.1"
.ShouldValidateTo(RequestValidationStatus.Ok);
}

The drawback of using extension methods is when you want to have optional state setup methods that you can chain together to form an expression.

[Test]
public void Validate_RequestWithValidPath_Ok()
{
"GET /valid/path.html HTTP/1.1"
.UsingPathChecker(new AlwaysValidPathChecker())
.ShouldValidateTo(RequestValidationStatus.Ok);
}

If the UsingPathChecker method in the example above needs to be optional you have to supply two extension methods to the string class, UsingPathChecker and ShouldValidateTo. You also need a class that is used as a return value of the UsingPathChecker method call, which holds the state and also contains a ShouldValidateTo method.

As you can see, it can quickly get a bit messy. To get rid of some of the mess, you can use a simple factory method with a well chosen name.

[Test]
public void Validate_RequestWithValidPath_Ok()
{
TheRequest("GET /valid/path.html HTTP/1.1")
.UsingPathChecker(new AlwaysValidPathChecker())
.ShouldValidateTo(RequestValidationStatus.Ok);
}

The method TheRequest in this example simply returns a new instance of the helper class which holds the state, and thereby eliminates the need for the extension methods. You now only have one place where you can put all the stuff you need to create your little DSL.

Here is an example of what the helper class could look like:

class HttpRequestValidatorSpecsIntermediary
{
string _input;
private HttpRequestValidator _validator;

internal HttpRequestValidatorSpecsIntermediary(string input)
{
_input = input;
_validator = new HttpRequestValidator();
}

internal HttpRequestValidatorSpecsIntermediary UsingPathChecker(IPathChecker pathChecker)
{
_validator = new HttpRequestValidator(pathChecker);

return this;
}

internal void ShouldValidateTo(RequestValidationStatus expectedStatus)
{
var actualValidationStatus = _validator.Validate(new HttpRequest(_input));

Assert.AreEqual(expectedStatus, actualValidationStatus);
}
}

Written by Erik Öjebo 2010-03-29 19:56

    Comments