Specflow 1.9 mit Coded UI Tests verheiraten

Specflow und Gherkin sind sehr praktisch wenn es darum geht Tests zu verfassen und anschließend zu automatisieren. Dabei werden Tests klarsprachlich mit Gherkin formuliert und anschließend von Specflow in automatische Tests übertragen. Leider gibt es hier aber ein „kleines“ Problem bei der Zusammenarbeit mit den Coded UI Tests von Visual Studio. Diese verwenden, im Gegensatz zum sonst üblichen TestClass-Attribut, das Attribut CodedUITest.

Da Specflow für jede Feature Datei aber nur das TestClass Attribut verwendet, müssen wir nur also Hand anlegen und den Code Generator ein wenig erweitern. Wie man genau vorgeht ist bereits bei GitHub beschrieben, wo ich auch den Code für Version 1.9 nachgetragen habe. Ich würde das Vorgehen dennoch hier ein wenig ausführlicher beschreiben, damit es auch in Deutsch verfügbar ist.

  • Zuerst muss ein Visual Studio Projekt mit dem Namen Specflow.CodedUIUtility erstellt werden in dem „unser“ Generator hinterlegt wird. Dies sollte auf Basis der Runtime der aktuellen Specflow Version laufen, wobei es sich um .Net 3.5 handelt.
  • Jenes Projekt muss die Dlls TechTalk.SpecFlow.Generator.dll und TechTalk.SpecFlow.Utils.dll referenzieren. Die sich im Tools Verzeichnis des Specflow Packages befinden, welches man von NuGet herunter lädt.
  • Nun wird eine .cs Datei Namens MsTest2010CodedUiGeneratorProvider angelegt und folgender Code hinein kopiert.

namespace Specflow.CodedUIUtility
{
  using System.CodeDom;

  using TechTalk.SpecFlow.Generator;
  using TechTalk.SpecFlow.Generator.UnitTestProvider;
  using TechTalk.SpecFlow.Utils;

  public class MsTest2010CodedUiGeneratorProvider : MsTest2010GeneratorProvider
  {
    public MsTest2010CodedUiGeneratorProvider(CodeDomHelper codeDomHelper)
      : base(codeDomHelper)
    {
    }

    public override void SetTestClass(TestClassGenerationContext generationContext, string featureTitle, string featureDescription)
    {
      base.SetTestClass(generationContext, featureTitle, featureDescription);
      foreach (CodeAttributeDeclaration customAttribute in generationContext.TestClass.CustomAttributes)
      {
         if (customAttribute.Name == "Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute")
         {
            generationContext.TestClass.CustomAttributes.Remove(customAttribute);
            break;
         }
      }

      generationContext.TestClass.CustomAttributes.Add(
        new CodeAttributeDeclaration(new CodeTypeReference("Microsoft.VisualStudio.TestTools.UITesting.CodedUITestAttribute")));
    }
  }
}
  • Nachdem diese Dll kompiliert wurde, wird sie dann in das Tools Verzeichnis des NuGet packages von Specflow kopiert.
  • Anschließend muss der Inhalt der App.Config des Projekts mit den Tests durch folgendes Xml ersetzt werden.
<configuration>
  <configSections>
    <section name="specFlow"
    type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler,
    TechTalk.SpecFlow"/>
  </configSections>
  <specFlow>
<unitTestProvider
 name="MsTest.2010"
generatorProvider="Specflow.CodedUIUtility.MsTest2010CodedUiGeneratorProvider,
Specflow.CodedUIUtility"
 runtimeProvider="TechTalk.SpecFlow.UnitTestProvider.MsTest2010RuntimeProvider,
 TechTalk.SpecFlow"/>
 </specFlow>
</configuration>
  • Nun muss das Testprojekt nur noch folgende Dlls referenzieren, wobei hier die Specflow Dll aus dem lib Verzeichnis des NuGet Packages zu verwenden ist:
    • Microsoft.VisualStudio.QualityTools.CodedUITestFramework
    • Microsoft.VisualStudio.QualityTools.UnitTestFramework
    • Microsoft.VisualStudio.TestTools.UITest.Common
    • Microsoft.VisualStudio.TestTools.UITest.Extension
    • Microsoft.VisualStudio.TestTools.UITesting
    • TechTalk.SpecFlow

Anschließend einfach eine Feature Datei anlegen und speichern, dabei sollte eine Code Behind Datei angelegt werden die eine Klasse mit dem Attribut CodedUITest enthält. Sollte statt dessen ein Fehlertext darin stehen, könnte es sein, dass entweder der Eintrag in der App.Config nicht stimmt oder die Datei mit dem Generator nicht in das korrekte Verzeichnis kopiert wurde.