Ease your SpecFlow pain with SpecSalad

By Mike Hanson at April 04, 2012 16:41
Filed Under: BDD, Acceptance Testing, Testing, Test Runners, SpecFlow

Just finished a contract where we used SpecFlow to define our acceptance tests, and I have been using it on my personal projects for a while.  Anyone using SpecFlow for a while quickly learns that you have to be careful how you organise your step definitions or you can get in a real mess.  It is a great tool but if you tend to just dive in without first finding out the best practice it can be painful.

 

Recently I discovered SpecSalad.  Duncan Butler has ported CukeSalad over to .NET for us and I for one am glad he did.  Basically SpecSalad takes the pain away by allowing you to define your system as a set of Roles and Tasks.  Steps are replaced by the Task and as each one is a separate class it is much easier to keep track or reuse.  I won’t regurgitate the “how to” as Duncan has some great posts on his blog to get you started.

 

SpecSalad necessarily constrains the vocabulary you must use, but this has a cool side effect of making it easier for new adopters of BDD to learn the vocabulary.  On my last project the vocabulary was somewhat of a hurdle for the business to getting on board and defining the acceptance tests, for much of it we the developers were defining acceptance tests after the fact, never a good thing in my book.

UI Automation Build Validation

By Mike Hanson at July 30, 2011 05:26
Filed Under: .NET, Testing, UI Automation, Visual Studio

On my last few contracts I have advocated acceptance testing through UI automation, but one of the most common wishes expressed by those coding up tests was for some way to validate that our automation wrappers actually still reflected the control they wrapped in the application under test.  Something as simple as renaming a button would break our tests.  It wasn’t until the next scheduled run of our acceptance tests that the breakage would be identified.

 

As mentioned in my last post I am working on a Windows Automation Toolkit (WATKit), I haven’t finished it yet but I figured an early feature should be some kind of build time validation to resolve the above issues.  As of today WATKit includes an MSBuild Task and a few attributes to do just that.

 

WATKitBuildTask

 

The build task basically compares types in a test assembly that are decorated with AutomationTypeMappingAttribute against elements on types in one or more source assemblies.  The test assembly and source assemblies are specified in the build configuration file (aka VS 2010 project file).  Here is the what I added to the WATKit.Tests.csproj file in the WATKit source available on GitHub:

 

   1: <UsingTask TaskName="WATKIt.Build.WATKitBuildTask"
   2:             AssemblyFile="$(TargetDir)\WATKit.dll"/>
   3:   <Target Name="AfterBuild">
   4:         <WATKitBuildTask TestAssembly="$(TargetDir)WATKit.Tests.dll"
   5: SourceAssemblies="$(SolutionDir)\WATKit.TestApp.WPF\bin\Debug\WATKit.TestApp.exe" />
   6:         <WATKitBuildTask TestAssembly="$(TargetDir)WATKit.Tests.dll"
   7: SourceAssemblies="$(SolutionDir)\WATKit.TestApp.WinForms\bin\Debug\WATKit.TestApp.exe" />
   8:   </Target>

 

So the first thing it does is reference the build task with a <UsingTask /> element.  With this in place the task can be referenced as an element within any <Target /> element.  I simply uncommented the AfterBuild target that is included in most project files.  I have the task running to validate against the two test apps in the solution.

 

The build task has two required properties:

 

TestAssembly points to the assembly containing the wrappers to be validated.  It doesn’t have to be a test assembly, if you keep your wrappers in a separate class library then it is this library you should reference.

 

SourceAssemblies is a comma separated list of one or more assemblies that contain real controls and windows.  It works with WPF and WinForms applications (I haven’t tested it on other project types, I don’t see any reason it won’t work with Silverlight 4.* assemblies, but I haven’t tested it yet)

 

AutomationTypeMappingAttribute

 

In the test assembly only types with the AutomationTypeMappingAttribute are checked.  Each Property on these types is checked unless it is decorated with an IgnoreAttribute.  Methods and Fields are implicitly ignored.

 

This attribute has a single constructor argument that must be a fully qualified name of the type to validate against in one of the source assemblies.  For example the MainWindow wrapper control in the WATKit.Tests project is declared like this:

   1: [AutomationTypeMapping("WATKit.TestApp.MainWindow")]
   2: public class MainWindow : Window
   3: {
   4: }

This tells the build task to validate MainWindow in the test assembly against the first WATKit.TestApp.MainWindow it finds in the source assemblies (the search is carried out in the order assemblies are listed)

 

IgnoreAttribute

 

By default the build task will check every Property on the wrapper type unless you tell it otherwise by decorating a Property with this attribute.  You can optionally specify a Reason for ignoring it, so that others will know why.  For example the DynamicButton property of MainWindow mentioned above looks like this:

   1: [Ignore(Reason = "Button does not exist until run time")]
   2:  public Button DynamicButton { get { // removed for brevity } }

Many properties in the base classes in WATKit are decorated with this attribute to avoid build failures.

 

AutomationMemberAttribute

 

By default the build task will look for an exact match of the wrapper Property name with the name of a Field (child controls in WPF and WinForms are exposed as fields not properties) in the type it is validating against.  If for some reason the names do not match you can decorate the wrapper property with this attribute and specify the name to match.  For example the ChangeMyNameButton property of MainWindow mentioned above looks like this:

   1: [AutomationMemberMapping("IChangeMyNameButton")]
   2: public Button ChangeMyNameButton { get { // removed for brevity } }

This tells the build task to validate the ChangeMyNameButton property against a field named IChangeMyNameButton.

 

That’s it, no rocket science but it does the job and based on my experiences should help to give early feedback about breaking changes in applications being tested via UI Automation.  The build task is not limited to use with tests that use features of WATKit, it should work with any automation framework as long as you create wrappers for your controls and those wrappers expose properties representing child controls and elements exposed by the real types.

 

If you have any feedback or suggestions for improving this please let me know by commenting here or over at GitHub.

WebAii and FitNesse

By Mike Hanson at October 14, 2010 21:13
Filed Under: .NET, Silverlight, Testing

Well now I am getting seriously worried.  After I got so far with automated UI testing with WebAii and NUnit I thought I was finished as the Automation Master on my team and could get on with some interesting work.  Oh no while I was down with a heavy dose of Man Flu the team decided to use FitNesse for defining acceptance tests and they want me to integrate this with the WebAii tests.  I guess their argument that I was the one with most experience of test automation so I will be up and running quicker is valid, but it worries me that I am doing so much testing and only a little programming.

 

If you are not familiar with it FitNesse is basically a Wiki that supports defining acceptance tests as tables of inputs and outputs and links to a test runner to execute the tests.  That is a bit of an over simplification but it will do for now.

 

It didn’t take long to get FitNesse setup so I started looking at how we could use it in conjunction with WebAii.  That took a while longer I figured out a way to do it and managed to port some of my existing code over to get a first test running.

 

So now my series on Silverlight Testing with WebAii will be at least one episode longer as I will include an extra one on how to get this done.

Tag cloud

Previous Articles