I was looking into using the ObjectMother 'pattern' if it can be called that to deal with the mountains of repetitive code that has been accruing in one of my projects. Unfortunately I saw that it was difficult to deal with changing commonly variant properties for testing purposes and then I came across this which more or less agrees with that observation.
Some background : I work alone and so any friction that appears for me to setup a test automatically reminds me how behind I am on this project and so I am more tempted to 'just write good code' and rely on my prayer life more :). A huge deterrent to me is especially in my NHibernate integration testing whereby I must deal with actual concrete classes that are valid. I use RhinoMocks so enjoy my unit testing, but integration testing to me somehow has become ranked alongside enemas in terms of things I enjoy.
Then it comes time for actual web testing for feedback and so on...sheesh, here comes more trash code to just get 'er done. Enter the solution Nat proposes.
Nat's article I referenced uses a simple builder pattern to help keep the sample test data scalable and shielded away as much as possible from possibly volatile constructor signatures. The first step was to decide how the dependencies required my packages (assembly) would appear:
The only interesting thing here is the consumption of TestDataBuilder from my Web app project. This allows me to stop writing so much repetitive object creation code and reuse existing methods to hydrate my db for client demos and so on.
The single biggest benefit of either the ObjectMother or this pattern when compared to raw DDL, though, is the power of refactoring tools like Resharper to keep tests from becoming stale or broken. Working alone, I simply have to have those kinds of shortcuts at my fingertips or else I simply will not write tests. I know mine-self :)
When complex object graphs appear, the builder pattern really allows for a great deal of flexibility . For example, here is my EmployeeBuilder that consumes other builders to do its work:
1: public class EmployeeBuilder
2: { 3: private IEnterpriseDepartment _enterpriseDepartment;
4: private IEnterprise _enterprise = new EnterpriseBuilder().Build();
5: private IPerson _person = new PersonBuilder().Build();
6: public EmployeeBuilder ForEnterprise(IEnterprise enterprise)
7: { 8: _enterprise = enterprise;
9: return this;
10: }
11:
12: public IEmployee Build()
13: { 14: _enterpriseDepartment = new EnterpriseDepartmentBuilder().ForEnterprise(_enterprise).Build();
15: return _enterprise.AddEmployee(_person, _enterpriseDepartment);
16: }
17: }
18: //EnterpriseDepartmentBuilder
19: public class EnterpriseDepartmentBuilder
20: { 21: private IEnterprise _enterprise = new EnterpriseBuilder().Build();
22: private string _name="EntDept";
23: private string _deptCode="12";
24: private bool _isGandA;
25:
26:
27: public EnterpriseDepartmentBuilder WithName(string name)
28: { 29: _name = name;
30: return this;
31: }
32: public EnterpriseDepartmentBuilder ForEnterprise(IEnterprise enterprise)
33: { 34: _enterprise = enterprise;
35: return this;
36: }
37: public IEnterpriseDepartment Build()
38: { 39: return _enterprise.AddDepartment(_name, "DeptDescription", _deptCode, _isGandA);
40: }
41: }
An IEmployee may only be created by its aggregate, the IEnterprise. The same is true for an IEnterpriseDepartment. The two builder classes above show how easy it is to deal with these kinds of rules while still allowing for the variations of object creation to scale as test requirements demand.
How have you dealt with injecting data for testing or demo purposes that was useful?
Posted
09-28-2007 12:22 AM
by
Michael Nichols