NuGet package! I am so proud. Actually it’s just a
small extension to SpecFlow and the excellent Assist helpers by
Darren Cauthon.
But I learned quite a lot about dynamics in the process and I thought I
write a post or two on
SpecFlow.Assist.Dynamic; what it is, the problem it
solves and how it’s made. Later post will be around how to use it and to
put it together with Simple.Data to create a real sweet testing
experience.
Let me say – before I start – that there is
documentation for usage on the GitHub wiki. This is
a blog posts on how I made
SpecFlow.Assist.Dynamic – not the official
documentation.
The problem
It’s not a very big problem I’ve solved – but I grew tired of writing
small classes that just was for transporting data. For example for the
Gherkin-step:
```
1: Given the following users exists in the database:
```
```
2: | Name | Age | Birth date | Length in meters |
```
```
3: | Marcus | 39 | 1972-10-09 | 1.96 |
```
```
4: | Albert | 3 | 2008-01-24 | 1.03 |
```
```
5: | Gustav | 1 | 2010-03-19 | 0.84 |
```
```
6: | Arvid | 1 | 2010-03-19 | 0.85 |
```
I need to implement the following step-definitions (note that I’m using
the SpecFlow.Assists table extension methods here to
keep things short):
```
1: [Binding]
```
```
2: public class DemoSteps
```
```
3: {
```
```
4: [Given(@"the following users in the database")]
```
```
5: public void x(Table table)
```
```
6: {
```
```
7: IEnumerable
listOfUsers = table.CreateSet();
```
```
8:
```
```
9: // insert in database code goes here
```
```
10: //foreach (var user in listOfUsers)
```
```
11: //{
```
```
12: // user.Name, user.Age
```
```
13: //}
```
```
14: }
```
```
15: }
```
```
16:
```
```
17: public class User
```
```
18: {
```
```
19: public string Name { get; set; }
```
```
20: public int Age { get; set; }
```
```
21: public DateTime BirthDate { get; set; }
```
```
22: public double LengthInMeters { get; set; }
```
```
23: }
```
So the actual step definition is pretty concise and slick. And actually
the only thing that bothers me is that class User. It’s only needed by
the step definition and it’s only purpose is to transport some data.
The solution
As I started to use Simple.Data I realized that
dynamics could solve this problem for us. So that
instead can write:
1:
\[Binding\]
```
2: public class DemoSteps
```
```
3: {
```
```
4: [Given(@"the following users in the database")]
```
```
5: public void x(Table table)
```
```
6: {
```
```
7: IEnumerable
listOfUsers = table.CreateDynamicSet();
```
```
8:
```
```
9: // insert in database code goes here
```
```
10: //foreach (var user in listOfUsers)
```
```
11: //{
```
```
12: // user.Name, user.Age
```
```
13: //}
```
```
14: }
```
```
15: }
```
Just the code we need. No extra data carriers. Of course you’ll
sacrifice intellisense, which is a big hurdle for a lot of us. But I got
used to it – so can you.
How to get it
The easiest way, by far, is to
download it via NuGet.:
> style="font-family: monospace;">Install-Package
> SpecFlow.Assist.Dynamic
If you want to help out…you are more than welcome. I’m not planning on
doing any more work on this right now. But I hope that you see a bug or
a improvement possibilities.
Let me know via GitHub
How it’s made
The first thing I did was actually to write
SpecFlow scenarios for how I wanted the new
functionality to work. Even though this was a good thing, as test first
is, I would not recommend using
SpecFlow to test out unit level stuff. The major
benefit with SpecFlow and Cucumber, if you ask me, is that
business users can read and understand the specifications.
After that I simply created new
extension methods on the
SpecFlow Table object:
```
1: public static IEnumerable
CreateDynamicSet(this Table table)
```
One for each of the new features I wanted to support, four in all:
- **CreateDynamicInstance** – creates an instance from a table. This
can be done either for tables with one row or with two column
tables.
In the case of one row tables the header values are used as property
names.
In the case of the two column table the first column is presumed to
contain the property values and the second the values for those
properties (for examples see this)
- **CreateDynamicSet** – creates a IEnumerable\<dynamic\> for a
several rows. The headers are the property names as before.
- **CompareDynamicInstance** (to table) – this compares a instance of
a object you send to the method to a table. The table is parsed
using the CreateDynamicInstance–method as above.
- **CompareDynamicSet** – and finally you can compare a set of object
to a table. The table is parsed using the CreateDynamicSet method as
above.
So, I have tried to use the same conventions as the one used in the
SpecFlow.Assist helpers;
- Spaces can be used in table headers but are removed in property
values (“Birth Date” becomes “BirthDate” for example)
- I uppercase every new word even though it’s not like that in the
table. So “Birth date” in the table header becomes “BirthDate” on
the dynamic object
I also added a convention of my own that has to do with types on the
dynamic object. I try to parse types from the values in the table in
this order:
- First try to parse it as a DateTime
- Then as a Integer
- Then as a Double
- And as a fall back I use a string
I wanted to do this to be able to do some more safe comparisons etc.
Challenges and solutions in
the implementation
Creating
object properties from header strings
One of the first tricks I learned about is the ExpandoObject. By reading up on this I learned a lot
about how dynamics actually works.
**First** – the keyword “dynamic” only means “don’t do compile-time
checking for this variable, it will work in runtime”. Nothing more.
**Secondly** - the base class for a lot of the cool the stuff in
System.Dynamics – DynamicObject – is simply a wrapper that gives you
the possibility to trap exceptions for when you are accessing members
not present on the current object. So if I have written:
```
1: dynamic a = new MyDynamicObject();
```
```
2: a.Name = "Marcus";
```
I’m simply telling the compiler to let me write anything on the “a”
object reference. So it swallows the ‘a.Name = “Marcus”’ statement
without complaining.
In order to handle that I can write this simple class, inheriting from
DynamicObject:
```
1: public class MyDynamicObject : DynamicObject
```
```
2: {
```
```
3: public override bool TryGetMember(GetMemberBinder binder, out object result)
```
```
4: {
```
```
5: return base.TryGetMember(binder, out result);
```
```
6: }
```
```
7: }
```
In the TryGetMember override I can handle access to any member and do
something more useful than to crash with a “Member not defined”.
And that’s exactly what ExpandoObject does. It simply stores all the
members, and their value, that you access into an internal
IDictionary\<string, object\>. In fact you can even cast an
ExpandoObject into a Dictionary\<string, object\> and insert your
members that way.
And that’s how I insert new dynamic properties and their values from
each table row. Like this:
```
1: private static ExpandoObject CreateDynamicInstance(TableRow tablerow)
```
```
2: {
```
```
3: dynamic expando = new ExpandoObject();
```
```
4: var dicExpando = expando as IDictionary<string, object>;
```
```
5:
```
```
6: foreach (var header in tablerow.Keys)
```
```
7: {
```
```
8: var propName = CreatePropertyName(header);
```
```
9: var propValue = CreateTypedValue(tablerow[header]);
```
```
10: dicExpando.Add(propName, propValue);
```
```
11: }
```
```
12:
```
```
13: return expando;
```
```
14: }
```
Comparing
dynamic objects
One problem that almost stumped me was how to compare dynamic instances.
There is no way to check which properties a dynamic instance has. … In
the .NET framework. … That I know of.
But I found the Impromptu Interface project (and
NuGet package). It does a lot of marvelous and
strange things but I used it to GetMemberNames. That’s a static method
that take an object and returns a list of it’s members.
And there’s also a method that invoke methods on any object by name –
InvokeSet(object, memberName).
Combining these two made it a lot easier to write the comparisons
methods for dynamic instances and sets.
Reflection
But it was also around this place (having to take a dependency on
ImpromtuInterface) that I realized that my solution might be the wrong
one. I’m wondering if I might have been closer to a pure “dynamic by the
book” solution if I had done a class inheriting from DynamicObject
called DynamicSpecFlowTable. In that class I could easier and cleaner
have handle how properties are set and comparisions done…
Well it works fine now. I’ll keep it like this.
The future
Actually I would not like to have this NuGet package. I would rather see
this included in the SpecFlow main source. But as for now that means that
SpecFlow needs to take a dependency on
ImpromtuInterface and that’s probably not what they want.
So this has been my training ground for a small adventure in
dynamic-land. I’ve enjoyed it.
I hope you do too.