This is the second post about
SpecFlow.Assist.Dynamic – a little tool I wrote to
help you write less code in your step definitions, and focus on the
actual step instead of infrastructure. You can read the first post
here
– it explains little about what
SpecFlow.Assist.Dynamic is.
In this post I’ll show you how some ways I use the dynamic features to
and some tricks that you might not know about.
Again – this is not the documentation for SpecFlow.Assist.Dynamic –
that can be found here.
Installation
With the power of
NuGet it’s
super-easy to install SpecFlow.Assist.Dynamic by simply go:
Install-Package SpecFlow.Assist.Dynamic
(Sidenote: Ha! It’s good to try out your own stuff. Found a bug in the
0.2 version on NuGet. Fixed it with the 0.2.1 version )
That will also pull down the latest version of
SpecFlow and other dependencies needed.
Test data management
I found out that the most maintainable way to write scenarios is to have
them initialize their own test data. Or at least on the feature level.
I’ve tried to do it by restoring back ups but that has two drawbacks.
First – it takes too long. And test that takes too long are not run.
Secondly – the features (specifications?) are not easy to follow. You
have to know what test data is being read back. It’s hidden for most
users.
So why do we still try this approach? Laziness I guess… It’s just to
much code to write.
Adding test data – single instances
There are two main features where
SpecFlow.Assist.Dynamic helps you; adding test data
in the Given-steps and comparing the outcome to the test data in you
Then-steps.
For example for this Given step:
```
1: Scenario: Searching for books
```
```
2: Given the following books in the system
```
```
3: | Title | Author | ISBN |
```
```
4: | The Goal | Eliah Goldratt | 123345678 |
```
```
5: | Stick | Ted and Dan Heath | 9955663322 |
```
```
6: | The Good book | God et. al | 1 |
```
I can write the following short statements with
SpecFlow.Assist.Dynamic:
```
1: [Binding]
```
```
2: public class DemoSteps
```
```
3: {
```
```
4: [Given(@"the following books in the system")]
```
```
5: public void GivenTheFollowingBooksInTheSystem(Table table)
```
```
6: {
```
```
7: IList
books = table.CreateDynamicSet().ToList();
```
```
8: foreach (var book in books) { DBHelper.AddBook(book); }
```
```
9: }
```
```
10: }
```
```
11:
```
```
12: public class DBHelper
```
```
13: {
```
```
14: public static void AddBook(dynamic book)
```
```
15: {
```
```
16: var insertStatement = string.Format(
```
```
17: "INSERT INTO BOOKS (Title, Author, ISBN) VALUES ('{0}', '{1}', '{2}')",
```
```
18: book.Title, book.Author, book.ISBNNumber);
```
```
19:
```
```
20: // Call into the db...
```
```
21: }
```
```
22: }
```
There’s a lot to be said about the data access code, for example you
probably are using an ORM of sorts and hopefully you can send dynamic
objects to it. I’ll show other ways to do that later.
Let’s focus on the
SpecFlow.Assist.Dynamic instead. It’s not much to it
– I simply create a list of dynamic objects and use my DBHelper to
insert each one into the database.
Shorten it up with Step
Argument Transformations
You can use a trick that I’ve put into
SpecFlow.Assist.Dynamic to shorten the code even
further. There is a SpecFlow feature called Step Argument Transformation that I use to shorten
up code like the one above. With step argument transformation you can
create small conversion methods that is triggered when certain types is
used.
I have supplied three such argument transformations that converts Table
arguments into:
- A dynamic instance
- A IEnumerable\<dynamic\>
- A IList\<dynamic\>
So the example above can be written like this, using these step argument
transformations:
```
1: [Given(@"the following books in the system")]
```
```
2: public void GivenTheFollowingBooksInTheSystem(IList
books)
```
```
3: {
```
```
4: foreach (var book in books) { DBHelper.AddBook(book); }
```
```
5: }
```
Pretty slick, huh? This is how it works:
- SpecFlow matches my Given statement with the
Step definition marked with the Given-attribute above.
- From the .feature-file it knows that a table is sent to the step. It
send that table.
- In the
SpecFlow.Assist.Dynamic** **dll step argument
methods are found that matches a Table and the IList\<dynamic\> that
I am using in the method signature
- SpecFlow converts my argument using that method
and simply returns a IList\<dynamic\> containing the data from the
table.
You can read more about this on my wiki.
Oh yeah – **very important**! To get this to work you need to add a
configuration into your app.config:
```
1:
```
```
2:
```
```
3:
```
```
4:
```
```
5:
```
This make sure that the step arguments are picked up from the dll.
Asserting results in the
Then-steps
The other place where
SpecFlow.Assist.Dynamic shines is when you are
asserting that certain result of an action has happened.
If we expand my example from before in to a fully fledged feature, we
get this:
1:
Scenario: Searching for books
```
2: Given the following books in the system
```
```
3: | Title | Author | ISBN Number |
```
```
4: | The Goal | Eliah Goldratt | 123345678 |
```
```
5: | Stick | Ted and Dan Heath | 9955663322 |
```
```
6: | The Good book | God et. al | 1 |
```
```
7: When I search for Titles containing 'Goal'
```
```
8: Then the results should show the following books
```
```
9: | Title | Author | ISBN Number |
```
```
10: | The Goal | Eliah Goldratt | 123345678 |
```
I can now write the following steps:
```
1: [Binding]
```
```
2: public class DemoSteps
```
```
3: {
```
```
4: private IList
_books;
```
```
5: private IEnumerable _filteredBooks;
```
```
6:
```
```
7: [Given(@"the following books in the system")]
```
```
8: public void GivenTheFollowingBooksInTheSystem(IList books)
```
```
9: {
```
```
10: foreach (var book in books) { DBHelper.AddBook(book); }
```
```
11: _books = books;
```
```
12: }
```
```
13:
```
```
14: [When(@"I search for Titles containing '(.*)'")]
```
```
15: public void PerformTitleSearch( string value)
```
```
16: {
```
```
17: _filteredBooks = from b in _books
```
```
18: where b.Title.Contains(value)
```
```
19: select b;
```
```
20: }
```
```
21:
```
```
22: [Then(@"the results should show the following books")]
```
```
23: public void ResultsContainsBooks(Table table)
```
```
24: {
```
```
25: table.CompareToDynamicSet(_filteredBooks.ToList());
```
```
26: }
```
```
27: }
```
Don’t worry about the Given and When-steps, it’s just fake. I have save
the original list into a private variable called \_books and then simply
filter that out in the When-step. In a real example the When-step would
probably hit a webpage or a controller that in turn reads the database.
And the Given-step would put the right data into the database before
that.
But the interesting (and short!) stuff is the one liner in the
Then-step. Here I can again use the power of
SpecFlow.Assist.Dynamic and simply compare the
sent-in table to the result of my When-action.
And before you start to think about it. This way of writing it is easier
than to use the step argument transformations and compare two
IList\<dynamic\> to each other. That will be a lot more code.
### What about single instances?
I have now only showed you the use for Sets. There’s similar methods for
creating instances. Typically they are used to fill out forms or find a
certain record in the database.
I leave the usage of those methods as a creative exercise for the
reader. Let me know if you did anything that helped you.
### Conclusion
### I have shown you how I use these helpers. Please note that they are inspired to a great deal by the Table helpers in the SpecFlow.Assist namespace that have similar methods but for statically typed objects (that you need to create ^^)
I hope you find this helpful. Please let me know if I can improve.
In the [next
post](http://www.marcusoft.net/2011/11/specflowassistdynamicmaxing-out-with.html)
I’ll show a final thing that marries this with
Simple.Data. See you then.