Code-free .NET Coded UI Testing with SpecFlow

Using SpecFlow with a Coded UI API is already a well-worn path, according to the guys from Specflow.org. Yet after reading their post I was frustrated by how much C# code is involved; a tester shouldn’t be expected to do all of that. I’d like to propose this code sample for a class which can replace the entire last attached blog post.

The last step definition you’ll ever need to run Coded UI tests

Forget about that last blog post attached to the SpecFlow wiki, if you don’t care about parameterizing your action recordings you can throw it away. Instead take this class and add it to your project:

using Microsoft.VisualStudio.TestTools.UITesting;	
using System;	
using System.Collections.Generic;	
using System.Diagnostics;	
using System.Linq;	
using System.Reflection;	
using TechTalk.SpecFlow;	
	
namespace SpecflowAndCodedUI.StepDefinitions	
{	
    [Binding]	
    public class StepDefinitions	
    {	
        [Given(@"I '(.*)'")]
        [When(@"I '(.*)'")]
        [Then(@"I '(.*)'")]
        public void PerformAnyRecordedAction(string p0)
        {
            List allTypes = Assembly.GetExecutingAssembly().GetTypes().ToList();
            List allFoundMethods = new List();
            List allFoundUIMapTypes = new List();
            foreach (Type type in allTypes)
            {
                if (type.GetMethod(p0) != null)
                {
                    allFoundMethods.Add(type.GetMethod(p0));
                    allFoundUIMapTypes.Add(type);
                }
            }

            var countAllMethods = allFoundMethods.Count();
            if (countAllMethods == 1)
            {
                var foundActionRecording = allFoundMethods.First();
                var foundUIMapType = allFoundUIMapTypes.First();
                foundActionRecording.Invoke(Activator.CreateInstance(foundUIMapType), new object[] { });
            }
            else if (countAllMethods > 1)
            {
                throw new InvalidOperationException("Cannot distinguish between duplicated action recordings, named '" + p0 + "' in different UI maps.");
            }
            else if (countAllMethods <= 0)
            {
                throw new InvalidOperationException("Cannot find action recording named '" + p0 + "' in any UI map.");
            }
        }
    }
}

This is a very dynamic step definition which is flexible enough to find any recorded action without unnecessary extra work, making each and every action recording available. This set definition does not support parameterizing action recordings, but that doesn’t mean you can’t create and add your own. It does, however, realize the original goal of simplifying UI testing down to the point that a tester can record actions and immediately use them to define tests without the help of a developer. Although the SpecFlow wiki and blog posts will give you more control, this can teach you to parameterize your action recordings.

This step definition isn’t perfect

At first, this step definition may appear to be brute force. You’ll find, however, that as your UI Maps grow to very large sizes the need for this kind of force becomes apparent. Unfortunately, as you can see, this function does have to use reflection. It accepts a string and searches through a list of all methods in the project for a method by that name.

As long as your UI Maps are defined in the same project as this step definition it will be able to find all the action recordings in that UI Map. This means that as soon as any action recording is saved to any UI map in that project, it can be used in any feature file, by name, and no further work is needed to make them available to SpecFlow. This is quite different to the method described in the SpecFlow wiki, there you are expected to extensively refactor the methods to make them available to SpecFlow.

By writing a custom MsTest2010CodedUiGeneratorProvider for SpecFlow, instead of the one described in the SpecFlow wiki, this new Coded UI test generator can then replace all the step definition file described in this blog post. This method will also boost the performance at run time by running the step definition. This involves reflection at design time by replacing the regular unit test generator, which also uses reflection anyway.

Another disadvantage of this step definition is that the SpecFlow test runner already uses reflection at run time to find this step definition. That’s the way the unit test generator for SpecFlow works. Then, once it’s found this step definition, it uses reflection again to find the appropriate action recording. Replacing the unit test generator with a decent Coded UI test generator would solve that.

Despite these disadvantages, this step definition worked well for me when a tester started having problems linking action recordings against Warewolf to the features he was defining. Often he would simply forget to link them or cause compile breaks because he didn’t fully understand C# code. This step definition replaced a gigantic switch statement I was using to execute action recordings by name.

Conclusion

So if you are using any step definitions at all to run Coded UI tests with SpecFlow, you should consider using this more dynamic approach than the officially recommended approach on the SpecFlow wiki. If you know of a more thorough custom Coded UI test generator for SpecFlow that can use UI maps please mention it in the comments section. If you’d like to keep up to date or even contribute Warewolf’s Coded UI, the project is on GitHub.

FacebookTwitterLinkedInGoogle+RedditEmail

Leave A Comment?