Skip to content

Commit 8823232

Browse files
committed
Updated the readme
1 parent 3d924d2 commit 8823232

File tree

1 file changed

+67
-75
lines changed

1 file changed

+67
-75
lines changed

README.md

Lines changed: 67 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -85,56 +85,53 @@ Prior to v2.0 this library was known as NTestDataBuilder.
8585

8686
3. Use the builder in a test, e.g.
8787

88-
var customer = new CustomerBuilder().WithFirstName("Robert").Build();
88+
var customer = new CustomerBuilder()
89+
.WithFirstName("Robert")
90+
.Build();
8991

9092
4. Consider using the Object Mother pattern in combination with the builders, see [my blog post](http://robdmoore.id.au/blog/2013/05/26/test-data-generation-the-right-way-object-mother-test-data-builders-nsubstitute-nbuilder/) for a description of how I use this library.
9193

92-
How can I create a list of entities using my builders?
93-
------------------------------------------------------
94+
## How can I create a list of entities using my builders?
9495

9596
This library allows you to build a list of entities fluently and tersely. Here is an example:
9697

97-
```c#
9898
var customers = CustomerBuilder.CreateListOfSize(5)
9999
.TheFirst(1).WithFirstName("First")
100100
.TheNext(1).WithLastName("Next Last")
101101
.TheLast(1).WithLastName("Last Last")
102102
.ThePrevious(2).With(b => b.WithLastName("last" + (++i).ToString()))
103103
.All().WhoJoinedIn(1999)
104104
.BuildList();
105-
```
106105

107106
This would create the following (represented as json):
108107

109-
```json
110-
[
111-
{
112-
"FirstName":"First",
113-
"LastName":"LastNameff51d5e5-9ce4-4710-830e-9042cfd48a8b",
114-
"YearJoined":1999
115-
},
116-
{
117-
"FirstName":"FirstName7b08da9c-8c13-47f7-abe9-09b73b935e1f",
118-
"LastName":"Next Last",
119-
"YearJoined":1999
120-
},
121-
{
122-
"FirstName":"FirstName836d4c54-b227-4c1b-b684-de4cd940c251",
123-
"LastName":"last1",
124-
"YearJoined":1999
125-
},
126-
{
127-
"FirstName":"FirstName5f53e895-921e-4130-8ed8-610b017f3b9b",
128-
"LastName":"last2",
129-
"YearJoined":1999
130-
},
131-
{
132-
"FirstName":"FirstName9cf6b05f-38aa-47c1-9fd7-e3c1009cf3e4",
133-
"LastName":"Last Last",
134-
"YearJoined":1999
135-
}
136-
]
137-
```
108+
[
109+
{
110+
"FirstName":"First",
111+
"LastName":"LastNameff51d5e5-9ce4-4710-830e-9042cfd48a8b",
112+
"YearJoined":1999
113+
},
114+
{
115+
"FirstName":"FirstName7b08da9c-8c13-47f7-abe9-09b73b935e1f",
116+
"LastName":"Next Last",
117+
"YearJoined":1999
118+
},
119+
{
120+
"FirstName":"FirstName836d4c54-b227-4c1b-b684-de4cd940c251",
121+
"LastName":"last1",
122+
"YearJoined":1999
123+
},
124+
{
125+
"FirstName":"FirstName5f53e895-921e-4130-8ed8-610b017f3b9b",
126+
"LastName":"last2",
127+
"YearJoined":1999
128+
},
129+
{
130+
"FirstName":"FirstName9cf6b05f-38aa-47c1-9fd7-e3c1009cf3e4",
131+
"LastName":"Last Last",
132+
"YearJoined":1999
133+
}
134+
]
138135

139136
### Castle Dynamic Proxy Generator Exception error
140137

@@ -155,8 +152,8 @@ If you use the list builder functionality and get the following error:
155152
156153
Then you need to mark all the public methods on your builder as virtual. This is because we are using Castle Dynamic Proxy to generate lists and it can't intercept non-virtual methods.
157154

158-
Create Entities Implicitly
159-
--------------------------
155+
## Create Entities Implicitly
156+
160157
In the previous examples, you have seen how to create entities *explicitly*, by calling the `Build()` and `BuildList()` methods. For the ultimate in terseness, you can omit these methods, and Dossier will *implicitly* call them for you. The one caveat is that you must explicitly declare the variable type rather than using the `var` keyword (unless you are passing into a method with the desired type).
161158

162159
So, to create a single entity:
@@ -175,46 +172,48 @@ Or to create a list of entities:
175172
List<Customer> data = CustomerBuilder.CreateListOfSize(3)
176173
.TheFirst(1).WithFirstName("John");
177174

178-
Create object without requiring custom builder class
179-
----------------------------------------------------
175+
## Create object without requiring custom builder class
180176

181-
If you are building domain entities or other important classes having a custom builder class with intention-revealing method (e.g. WithFirstName) provides terseness (avoiding lambda expressions) and allows the builder class to start forming documentation about the usage of that object.
177+
If you are building domain entities, or other important classes, having a custom builder class with intention-revealing method (e.g. WithFirstName) provides terseness (avoiding lambda expressions) and allows the builder class to start forming documentation about the usage of that object.
182178

183179
Sometimes though, you just want to build a class without that ceremony. Typically, we find that this applies for view models and DTOs.
184180

185-
In that instance you can use the generic Builder implementation as shown below:
181+
In that instance you can use the generic `Builder` implementation as shown below:
182+
183+
StudentViewModel vm = Builder<StudentViewModel>.CreateNew()
184+
.Set(x => x.FirstName, "Pi")
185+
.Set(x => x.LastName, "Lanningham")
186+
.Set(x => x.EnrollmentDate, new DateTime(2000, 1, 1));
187+
188+
var studentViewModels = Builder<StudentViewModel>.CreateListOfSize(5)
189+
.TheFirst(1).Set(x => x.FirstName, "First")
190+
.TheNext(1).Set(x => x.LastName, "Next Last")
191+
.TheLast(1).Set(x => x.LastName, "Last Last")
192+
.ThePrevious(2).With(b => b.Set(x => x.LastName, "last" + (++i).ToString()))
193+
.All().Set(x => x.EnrollmentDate, _enrollmentDate)
194+
.BuildList();
186195

187-
```c#
188-
StudentViewModel vm = Builder<StudentViewModel>.CreateNew()
189-
.Set(x => x.FirstName, "Pi")
190-
.Set(x => x.LastName, "Lanningham")
191-
.Set(x => x.EnrollmentDate, new DateTime(2000, 1, 1));
196+
The syntax is modelled closely against what NBuilder provides and the behaviour of the class should be very similar.
192197

193-
var studentViewModels = Builder<StudentViewModel>.CreateListOfSize(5)
194-
.TheFirst(1).Set(x => x.FirstName, "First")
195-
.TheNext(1).Set(x => x.LastName, "Next Last")
196-
.TheLast(1).Set(x => x.LastName, "Last Last")
197-
.ThePrevious(2).With(b => b.Set(x => x.LastName, "last" + (++i).ToString()))
198-
.All().Set(x => x.EnrollmentDate, _enrollmentDate)
199-
.BuildList();
200-
```
198+
Note, that in the first example above, it was not necessary to call the `Build` method at the end of the method chain. This is because the `vm` variable has been defined as `StudentViewModel` and the C# compiler is able to infer the type and the object is set *implicitly*.
201199

202-
The syntax is modelled closely against what NBuilder provides and the behaviour of the class should be very similar.
200+
In the second example, the `var` keyword is used to define `studentViewModels`, and so it is necessary to *explicitly* call `BuildList` to set the variable.
203201

204202
### Customising the construction of the object
205203

206-
By default the longest constructor of the class you specify will be called and then all properties (with public and private setters) will be set with values you specified (or anonymous values if none were specified).
207-
208-
Sometimes you might not want this behaviour, in which case you can specify a custom construction factory (see build objects without calling constructor section for explanation of factories) as shown below:
204+
By default, the longest constructor of the class you specify will be called and then all properties (with public and private setters) will be set with values you specified (or anonymous values if none were specified).
209205

210-
```c#
211-
var dto = Builder<MixedAccessibilityDto>.CreateNew(new CallConstructorFactory()).Build();
206+
Sometimes you might not want this behaviour, in which case you can specify a custom construction factory (see *Build objects without calling constructor* section for explanation of factories) as shown below:
212207

213-
var dtos = MixedAccessibilityDto dto = Builder<MixedAccessibilityDto>.CreateListOfSize(5, new CallConstructorFactory()).BuildList();
214-
```
208+
var dto = Builder<MixedAccessibilityDto>
209+
.CreateNew(new CallConstructorFactory())
210+
.Build();
211+
212+
var dtos = MixedAccessibilityDto dto = Builder<MixedAccessibilityDto>
213+
.CreateListOfSize(5, new CallConstructorFactory())
214+
.BuildList();
215215

216-
Build objects without calling constructor
217-
-----------------------------------------
216+
## Build objects without calling constructor
218217

219218
When you extend the `TestDataBuilder` as part of creating a custom builder you will be forced to override the abstract `BuildObject` method. You have full flexibility to call the constructor of your class directly as shown above, but you can also invoke some convention-based factories to speed up the creation of your builder (also shown above) using the `BuildUsing` method.
220219

@@ -225,8 +224,7 @@ The `BuildUsing` method takes an instance of `IFactory`, of which you can create
225224
* `CallConstructorFactory` - Calls the longest constructor with builder values (or anonymous values if none set) based on case-insensitive match of constructor parameter names against property names
226225
* `AutoFixtureFactory` - Asks AutoFixture to create an anonymous instance of the class (note: does **not** use any builder values or anonymous values from Dossier)
227226

228-
Propogating the anonymous value fixture across builders
229-
-------------------------------------------------------
227+
## Propagating the anonymous value fixture across builders
230228

231229
Within a particular instance of `AnonymousValueFixture`, which is created for every builder, any generators that return a sequence of values (e.g. unique values) will be maintained. If you want to ensure that the same anonymous value fixture is used across multiple related builders then:
232230

@@ -258,13 +256,11 @@ Within a particular instance of `AnonymousValueFixture`, which is created for ev
258256

259257
There is currently no way to share an anonymous value fixture across unrelated builder instances. If this is something you need please raise an issue so we can discuss your requirement.
260258

261-
Anonymous Values and Equivalence Classes
262-
----------------------------------------
259+
## Anonymous Values and Equivalence Classes
263260

264261
todo: Coming soon!
265262

266-
How can I create proxy objects?
267-
-------------------------------
263+
## How can I create proxy objects?
268264

269265
This library integrates with [NSubstitute](http://nsubstitute.github.io/) for generating proxy objects, this means you can call the `AsProxy` method on your builder to request that the result from calling `Build` will be an NSubstitute proxy with the public properties set to return the values you have specified via your builder, e.g.
270266

@@ -275,7 +271,6 @@ This library integrates with [NSubstitute](http://nsubstitute.github.io/) for ge
275271

276272
If you need to alter the proxy before calling `Build` to add complex behaviours that can't be expressed by the default public properties returns values then you can override the `AlterProxy` method in your builder, e.g.
277273

278-
```c#
279274
class CustomerBuilder : TestDataBuilder<Customer, CustomerBuilder>
280275
{
281276
// ...
@@ -300,20 +295,17 @@ If you need to alter the proxy before calling `Build` to add complex behaviours
300295

301296
var customer = new CustomerBuilder().AsProxy().HasBeenMemberForYears(10);
302297
var years = customer.CustomerForHowManyYears(DateTime.Now); // 10
303-
```
304298

305299
*Remember that when using proxy objects of real classes that you need to mark properties and methods as virtual and have a protected empty constructor.*
306300

307-
Why does TestStack.Dossier have NSubstitute and AutoFixture as dependencies?
308-
------------------------------------------------------------------------
301+
## Why does TestStack.Dossier have NSubstitute and AutoFixture as dependencies?
309302

310303
TestStack.Dossier is an opinionated framework and as such prescribes how to build your fixture data, including how to build lists, anonymous data and mock objects. Because of this we have decided to bundle it with the best of breed libraries for this purpose: AutoFixture and NSubstitute.
311304

312305
This allows for this library to provide a rich value-add on top of the basics of tracking properties in a dictionary in the `TestDataBuilder` base class. If you want to use different libraries or want a cut down version that doesn't come with NSubstitute or AutoFixture and the extra functionality they bring then take the `TestDataBuilder.cs` file and cut out the bits you don't want - open source ftw :).
313306

314307
If you have a suggestion for the library that can incorporate this value-add without bundling these libraries feel free to submit a pull request.
315308

316-
Contributions / Questions
317-
-------------------------
309+
## Contributions / Questions
318310

319311
If you would like to contribute to this project then feel free to communicate with Rob via Twitter (@robdmoore) or alternatively submit a pull request / issue.

0 commit comments

Comments
 (0)