I want to put out a short sequel to my previous post on Active Conventions with NDepend. Also make sure to read Patrick Smacchia’s follow-up if your interested.
As you may or may not know, I’m a huge fan of using Test Data Builders for setting up the context for the domain objects in my BDD specifications.
[TestFixture] public class When_performing_something_action_with_an_order { [SetUp] public void Establish_context() { _order = new OrderBuilder() .WithCustomer(new CustomerBuilder() .WithFirstName("Homer") .WithLastName("Simpson")) .ForProduct(new ProductBuilder() .WithName("Saxomofoon")) } ... }
The biggest benefit of using the Builder pattern this way, is the fact that the creation of domain objects gets decoupled from the specifications itself. The constructor of a domain object gets called only at a single place in the code. If I wanted to add a new parameter to the constructor, I only have to change it in one place.
The following CQL statement ensures that the Test Data Builders are used instead of directly calling the constructors of the domain objects:
// <Name>Test data builders are not used by SetUp methods.</Name> WARN IF Count > 0 IN SELECT METHODS WHERE (HasAttribute "NUnit.Framework.SetUpAttribute" OR NameIs "Before_each_specification") AND ((IsDirectlyUsing "NAMESPACE:MyProject.Domain.Model" OR IsDirectlyUsing "NAMESPACE:MyProject.Domain.DTO") AND !IsDirectlyUsing "NAMESPACE:MyProject.Domain.UnitTests.Builders")
Although its probably not 100% foul proof, this CQL constraint detects the most blatant violations.
Till next time,
Jan, the NDepend addict.
I am not sure it’d help in your sample, but I precise there is a CreateA and DepthOfCreateA CQL conditions. For example, the following CQL rule make sure that there is no instance of Nm1.Foo created outside of namespace Nm2:
SELECT METHODS OUT OF NAMESPACES “Nm2” WHERE
DepthOfCreateA “Nm1.Foo” == 1
Thanks. I will have a look at that.