<?xml version="1.0" encoding="UTF-8"?>
<rss version='2.0' xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Steve Rushby</title>
    <description>Software Development &amp; Testing Blog</description>
    <link>https://rushby.silvrback.com/feed</link>
    <atom:link href="https://rushby.silvrback.com/feed" rel="self" type="application/rss+xml"/>
    <category domain="rushby.silvrback.com">Content Management/Blog</category>
    <language>en-us</language>
      <pubDate>Mon, 03 Apr 2017 10:54:19 +0100</pubDate>
    <managingEditor>steve@rushby.com (Steve Rushby)</managingEditor>
      <item>
        <guid>http://rushby.com/automation-with-geb-spock#27734</guid>
          <pubDate>Mon, 03 Apr 2017 10:54:19 +0100</pubDate>
        <link>http://rushby.com/automation-with-geb-spock</link>
        <title>UI Automation with Geb &amp; Spock (Part 1)</title>
        <description>Maven, Groovy, Selenium, IntelliJ</description>
        <content:encoded><![CDATA[<p>I&#39;ve recently moved on from a .Net software developer role have started working with Java.  A recent project requirement for the creation of a testing framework from scratch led to my discovery of the groovy based Geb wrapper (pronounced <em>jeb</em>) and the Spock framework. </p>

<p>Geb is described as <em>&quot;bringing together the power of WebDriver, the elegance of jQuery content selection, the robustness of Page Object modelling and the expressiveness of the Groovy language&quot;</em>.</p>

<p>Geb is a wrapper for the Selenium WebDriver API and works incredibly well with the testing and specification framework Spock.  Being from a .Net background I had never used things like Java (although it feels very familiar), Maven, POM files,  etc. so in this series of blog posts I will guide you through the set up process and build a specification based automated testing framework from scratch using Geb, Spock, Maven and the IntelliJ IDE.</p>

<h1 id="ui-automation-with-geb-spock-part-1-create-new-project">UI Automation with Geb &amp; Spock (Part 1): Create New Project</h1>

<p>1.  Add the Maven Integration plugin you haven&#39;t got it: <em>File -&gt; Settings... -&gt; Plugins</em><br>
    2.  Create a new Maven project using the <em>gmaven-archetype-basic</em> archetype </p>

<p><img alt="Silvrback blog image" src="https://silvrback.s3.amazonaws.com/uploads/f4ecae6f-76e5-47ab-ba09-9b47baca7870/NewProjectgmaven_large.jpg" /><br>
<em>Note: You will need to <a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html">download</a> the Java SDK if you haven&#39;t already, and set this in the Project SDK section at the top of the New Project window</em></p>

<p><em>Your project structure should look like this (with the sections highlighted in red being different depending on the name you gave your project) :</em></p>

<p><img alt="Silvrback blog image" src="https://silvrback.s3.amazonaws.com/uploads/7d64b2d6-c7af-4a58-92e9-062f2630676b/projectStructure_medium.jpg" /></p>

<p>2.  Clean up the project - delete the following:</p>

<ul>
<li>Example.groovy</li>
<li>Helper.groovy</li>
<li>ExampleTest.groovy</li>
<li>HelperTest.groovy</li>
</ul>

<p>3.      Set the <em>src/test/groovy</em> directory as the Test Sources Root:  </p>

<ul>
<li>Right click the groovy folder</li>
<li>Select <em>Mark Directory As</em> &gt; <em>Test Sources Root</em></li>
</ul>

<p><img alt="Silvrback blog image" src="https://silvrback.s3.amazonaws.com/uploads/0a58c3e3-6185-45a3-9d4f-a3910480ed33/testResourcesRoot_medium.jpg" /></p>

<p>4.  Delete the contents of the <a href="https://maven.apache.org/guides/introduction/introduction-to-the-pom.html">pom.xml</a> file after the <em>version</em> tag and before the closing <em>project</em> tag so it looks similar to this:</p>
<div class="highlight"><pre><span></span><span class="p">&lt;?</span><span class="n">xml</span> <span class="n">version</span><span class="p">=</span><span class="s">&quot;1.0&quot;</span> <span class="n">encoding</span><span class="p">=</span><span class="s">&quot;UTF-8&quot;</span><span class="p">?&gt;</span>

<span class="p">&lt;</span><span class="n">project</span> <span class="n">xmlns</span><span class="p">=</span><span class="s">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="n">xmlns</span><span class="p">:</span><span class="n">xsi</span><span class="p">=</span><span class="s">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span>
         <span class="n">xsi</span><span class="p">:</span><span class="n">schemaLocation</span><span class="p">=</span><span class="s">&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd&quot;</span><span class="p">&gt;</span>

    <span class="p">&lt;</span><span class="n">modelVersion</span><span class="p">&gt;</span><span class="m">4.0</span><span class="p">.</span><span class="m">0</span><span class="p">&lt;/</span><span class="n">modelVersion</span><span class="p">&gt;</span>

    <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">example</span><span class="p">-</span><span class="n">project</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">geb</span><span class="p">-</span><span class="n">automation</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="n">name</span><span class="p">&gt;</span><span class="n">ndds</span><span class="p">-</span><span class="n">automation</span> <span class="n">project</span><span class="p">&lt;/</span><span class="n">name</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="m">1.0</span><span class="p">-</span><span class="n">SNAPSHOT</span><span class="p">&lt;/</span><span class="n">version</span><span class="p">&gt;</span>

    <span class="p">&lt;!--</span> <span class="n">PASTE</span> <span class="n">FURTHER</span> <span class="n">XML</span> <span class="n">HERE</span> <span class="p">--&gt;</span>

<span class="p">&lt;/</span><span class="n">project</span><span class="p">&gt;</span>
</pre></div>
<p>Now we want to add in some property variables that will allow us to easily change the version of the geb, selenium and groovy packages. These should be added just below the <em>version</em> tag:</p>
<div class="highlight"><pre><span></span>    <span class="p">&lt;</span><span class="n">properties</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">gebVersion</span><span class="p">&gt;</span><span class="m">2.2</span><span class="p">&lt;/</span><span class="n">gebVersion</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">seleniumVersion</span><span class="p">&gt;</span><span class="m">3.14</span><span class="p">.</span><span class="m">0</span><span class="p">&lt;/</span><span class="n">seleniumVersion</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">groovyVersion</span><span class="p">&gt;</span><span class="m">2.5</span><span class="p">.</span><span class="m">3</span><span class="p">&lt;/</span><span class="n">groovyVersion</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">spockVersion</span><span class="p">&gt;</span><span class="m">1.2</span><span class="p">-</span><span class="n">groovy</span><span class="p">-</span><span class="m">2.5</span><span class="p">&lt;/</span><span class="n">spockVersion</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">project</span><span class="p">.</span><span class="n">build</span><span class="p">.</span><span class="n">sourceEncoding</span><span class="p">&gt;</span><span class="n">UTF</span><span class="p">-</span><span class="m">8</span><span class="p">&lt;/</span><span class="n">project</span><span class="p">.</span><span class="n">build</span><span class="p">.</span><span class="n">sourceEncoding</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">project</span><span class="p">.</span><span class="n">reporting</span><span class="p">.</span><span class="n">outputEncoding</span><span class="p">&gt;</span><span class="n">UTF</span><span class="p">-</span><span class="m">8</span><span class="p">&lt;/</span><span class="n">project</span><span class="p">.</span><span class="n">reporting</span><span class="p">.</span><span class="n">outputEncoding</span><span class="p">&gt;</span>
    <span class="p">&lt;/</span><span class="n">properties</span><span class="p">&gt;</span>
</pre></div>
<p>Below the closing <em>properties</em> tag we now want to add in the package dependencies we will need.  These are:</p>

<p><em>groovy-all</em> - contains the groovy libraries required to write groovy code<br>
<em>spock-core</em> - the testing and specification framework<br>
<em>geb-spock</em> - geb library with spock integration<br>
<em>selenium...</em> - the selenium browser drivers and support code</p>
<div class="highlight"><pre><span></span>        <span class="p">&lt;</span><span class="n">dependencies</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">dependency</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">codehaus</span><span class="p">.</span><span class="n">groovy</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">groovy</span><span class="p">-</span><span class="n">all</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="err">$</span><span class="p">{</span><span class="n">groovyVersion</span><span class="p">}&lt;/</span><span class="n">version</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="n">dependency</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">dependency</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">spockframework</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">spock</span><span class="p">-</span><span class="n">core</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="err">$</span><span class="p">{</span><span class="n">spockVersion</span><span class="p">}&lt;/</span><span class="n">version</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">scope</span><span class="p">&gt;</span><span class="n">test</span><span class="p">&lt;/</span><span class="n">scope</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">exclusions</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">exclusion</span><span class="p">&gt;</span>
                    <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">codehaus</span><span class="p">.</span><span class="n">groovy</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
                    <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">groovy</span><span class="p">-</span><span class="n">all</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
                <span class="p">&lt;/</span><span class="n">exclusion</span><span class="p">&gt;</span>
            <span class="p">&lt;/</span><span class="n">exclusions</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="n">dependency</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">dependency</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">gebish</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">geb</span><span class="p">-</span><span class="n">spock</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="err">$</span><span class="p">{</span><span class="n">gebVersion</span><span class="p">}&lt;/</span><span class="n">version</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">scope</span><span class="p">&gt;</span><span class="n">test</span><span class="p">&lt;/</span><span class="n">scope</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="n">dependency</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">dependency</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">seleniumhq</span><span class="p">.</span><span class="n">selenium</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">selenium</span><span class="p">-</span><span class="n">firefox</span><span class="p">-</span><span class="n">driver</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="err">$</span><span class="p">{</span><span class="n">seleniumVersion</span><span class="p">}&lt;/</span><span class="n">version</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">scope</span><span class="p">&gt;</span><span class="n">test</span><span class="p">&lt;/</span><span class="n">scope</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="n">dependency</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">dependency</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">seleniumhq</span><span class="p">.</span><span class="n">selenium</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">selenium</span><span class="p">-</span><span class="n">chrome</span><span class="p">-</span><span class="n">driver</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="err">$</span><span class="p">{</span><span class="n">seleniumVersion</span><span class="p">}&lt;/</span><span class="n">version</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">scope</span><span class="p">&gt;</span><span class="n">test</span><span class="p">&lt;/</span><span class="n">scope</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="n">dependency</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">dependency</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">seleniumhq</span><span class="p">.</span><span class="n">selenium</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">selenium</span><span class="p">-</span><span class="n">java</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="err">$</span><span class="p">{</span><span class="n">seleniumVersion</span><span class="p">}&lt;/</span><span class="n">version</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">scope</span><span class="p">&gt;</span><span class="n">test</span><span class="p">&lt;/</span><span class="n">scope</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="n">dependency</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">dependency</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">seleniumhq</span><span class="p">.</span><span class="n">selenium</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">selenium</span><span class="p">-</span><span class="n">support</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="err">$</span><span class="p">{</span><span class="n">seleniumVersion</span><span class="p">}&lt;/</span><span class="n">version</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">scope</span><span class="p">&gt;</span><span class="n">test</span><span class="p">&lt;/</span><span class="n">scope</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="n">dependency</span><span class="p">&gt;</span>
    <span class="p">&lt;/</span><span class="n">dependencies</span><span class="p">&gt;</span>
</pre></div>
<p><em>Note: Notice how the variables we added earlier are referenced using</em> <strong>${ }</strong> <em>e.g. ${seleniumVersion}</em></p>

<p>Next underneath the <em>dependencies</em> closing tag add the <em>build</em> section below which includes all the plugins required to get started:</p>
<div class="highlight"><pre><span></span>    <span class="p">&lt;</span><span class="n">build</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">plugins</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">plugin</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">apache</span><span class="p">.</span><span class="n">maven</span><span class="p">.</span><span class="n">plugins</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">maven</span><span class="p">-</span><span class="n">compiler</span><span class="p">-</span><span class="n">plugin</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="m">3.8</span><span class="p">.</span><span class="m">0</span><span class="p">&lt;/</span><span class="n">version</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">configuration</span><span class="p">&gt;</span>
                    <span class="p">&lt;</span><span class="n">source</span><span class="p">&gt;</span><span class="m">1.8</span><span class="p">&lt;/</span><span class="n">source</span><span class="p">&gt;</span>
                    <span class="p">&lt;</span><span class="n">target</span><span class="p">&gt;</span><span class="m">1.8</span><span class="p">&lt;/</span><span class="n">target</span><span class="p">&gt;</span>
                <span class="p">&lt;/</span><span class="n">configuration</span><span class="p">&gt;</span>
            <span class="p">&lt;/</span><span class="n">plugin</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">plugin</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">apache</span><span class="p">.</span><span class="n">maven</span><span class="p">.</span><span class="n">plugins</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">maven</span><span class="p">-</span><span class="n">surefire</span><span class="p">-</span><span class="n">plugin</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="m">2.22</span><span class="p">.</span><span class="m">1</span><span class="p">&lt;/</span><span class="n">version</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">configuration</span><span class="p">&gt;</span>
                    <span class="p">&lt;</span><span class="n">includes</span><span class="p">&gt;</span>
                        <span class="p">&lt;</span><span class="n">include</span><span class="p">&gt;**</span><span class="cm">/*Test.groovy&lt;/include&gt;</span>
<span class="cm">                        &lt;include&gt;**/</span><span class="p">*</span><span class="n">Spec</span><span class="p">.</span><span class="n">groovy</span><span class="p">&lt;/</span><span class="n">include</span><span class="p">&gt;</span>
                    <span class="p">&lt;/</span><span class="n">includes</span><span class="p">&gt;</span>
                    <span class="p">&lt;</span><span class="n">systemPropertyVariables</span><span class="p">&gt;</span>
                        <span class="p">&lt;</span><span class="n">geb</span><span class="p">.</span><span class="n">build</span><span class="p">.</span><span class="n">reportsDir</span><span class="p">&gt;</span><span class="n">target</span><span class="p">/</span><span class="n">test</span><span class="p">-</span><span class="n">reports</span><span class="p">/</span><span class="n">geb</span><span class="p">&lt;/</span><span class="n">geb</span><span class="p">.</span><span class="n">build</span><span class="p">.</span><span class="n">reportsDir</span><span class="p">&gt;</span>
                    <span class="p">&lt;/</span><span class="n">systemPropertyVariables</span><span class="p">&gt;</span>
                <span class="p">&lt;/</span><span class="n">configuration</span><span class="p">&gt;</span>
            <span class="p">&lt;/</span><span class="n">plugin</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">plugin</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">apache</span><span class="p">.</span><span class="n">maven</span><span class="p">.</span><span class="n">plugins</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">maven</span><span class="p">-</span><span class="n">assembly</span><span class="p">-</span><span class="n">plugin</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="m">3.1</span><span class="p">.</span><span class="m">0</span><span class="p">&lt;/</span><span class="n">version</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">executions</span><span class="p">&gt;</span>
                    <span class="p">&lt;</span><span class="n">execution</span><span class="p">&gt;</span>
                        <span class="p">&lt;</span><span class="n">id</span><span class="p">&gt;</span><span class="n">build</span><span class="p">-</span><span class="n">assembly</span><span class="p">&lt;/</span><span class="n">id</span><span class="p">&gt;</span>
                        <span class="p">&lt;</span><span class="n">phase</span><span class="p">&gt;</span><span class="n">compile</span><span class="p">&lt;/</span><span class="n">phase</span><span class="p">&gt;</span>
                        <span class="p">&lt;</span><span class="n">goals</span><span class="p">&gt;</span>
                            <span class="p">&lt;</span><span class="n">goal</span><span class="p">&gt;</span><span class="n">single</span><span class="p">&lt;/</span><span class="n">goal</span><span class="p">&gt;</span>
                        <span class="p">&lt;/</span><span class="n">goals</span><span class="p">&gt;</span>
                    <span class="p">&lt;/</span><span class="n">execution</span><span class="p">&gt;</span>
                <span class="p">&lt;/</span><span class="n">executions</span><span class="p">&gt;</span>
            <span class="p">&lt;/</span><span class="n">plugin</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">plugin</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">groupId</span><span class="p">&gt;</span><span class="n">org</span><span class="p">.</span><span class="n">codehaus</span><span class="p">.</span><span class="n">gmavenplus</span><span class="p">&lt;/</span><span class="n">groupId</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">artifactId</span><span class="p">&gt;</span><span class="n">gmavenplus</span><span class="p">-</span><span class="n">plugin</span><span class="p">&lt;/</span><span class="n">artifactId</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">version</span><span class="p">&gt;</span><span class="m">1.6</span><span class="p">.</span><span class="m">2</span><span class="p">&lt;/</span><span class="n">version</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">type</span><span class="p">&gt;</span><span class="n">maven</span><span class="p">-</span><span class="n">plugin</span><span class="p">&lt;/</span><span class="n">type</span><span class="p">&gt;</span>
            <span class="p">&lt;/</span><span class="n">plugin</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="n">plugins</span><span class="p">&gt;</span>
    <span class="p">&lt;/</span><span class="n">build</span><span class="p">&gt;</span>
</pre></div>
<p>Finally below the closing <em>build</em> tag add in the repositories (these are the locations used to download the dependencies):</p>
<div class="highlight"><pre><span></span>    <span class="p">&lt;</span><span class="n">pluginRepositories</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">pluginRepository</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">id</span><span class="p">&gt;</span><span class="n">central</span><span class="p">&lt;/</span><span class="n">id</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">name</span><span class="p">&gt;</span><span class="n">Central</span> <span class="n">Repository</span><span class="p">&lt;/</span><span class="n">name</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">url</span><span class="p">&gt;</span><span class="n">http</span><span class="p">:</span><span class="c1">//repo.maven.apache.org/maven2&lt;/url&gt;</span>
            <span class="p">&lt;</span><span class="n">layout</span><span class="p">&gt;</span><span class="k">default</span><span class="p">&lt;/</span><span class="n">layout</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">snapshots</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">enabled</span><span class="p">&gt;</span><span class="k">false</span><span class="p">&lt;/</span><span class="n">enabled</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">updatePolicy</span><span class="p">&gt;</span><span class="n">never</span><span class="p">&lt;/</span><span class="n">updatePolicy</span><span class="p">&gt;</span>
            <span class="p">&lt;/</span><span class="n">snapshots</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">releases</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">enabled</span><span class="p">&gt;</span><span class="k">false</span><span class="p">&lt;/</span><span class="n">enabled</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">updatePolicy</span><span class="p">&gt;</span><span class="n">never</span><span class="p">&lt;/</span><span class="n">updatePolicy</span><span class="p">&gt;</span>
            <span class="p">&lt;/</span><span class="n">releases</span><span class="p">&gt;</span>
     <span class="p">&lt;/</span><span class="n">pluginRepository</span><span class="p">&gt;</span>

     <span class="p">&lt;</span><span class="n">pluginRepositories</span><span class="p">&gt;</span>
    <span class="p">&lt;</span><span class="n">pluginRepository</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">id</span><span class="p">&gt;</span><span class="n">central</span><span class="p">&lt;/</span><span class="n">id</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">name</span><span class="p">&gt;</span><span class="n">Central</span> <span class="n">Repository</span><span class="p">&lt;/</span><span class="n">name</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">url</span><span class="p">&gt;</span><span class="n">http</span><span class="p">:</span><span class="c1">//repo.maven.apache.org/maven2&lt;/url&gt;</span>
        <span class="p">&lt;</span><span class="n">layout</span><span class="p">&gt;</span><span class="k">default</span><span class="p">&lt;/</span><span class="n">layout</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">snapshots</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">enabled</span><span class="p">&gt;</span><span class="k">false</span><span class="p">&lt;/</span><span class="n">enabled</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="n">snapshots</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">releases</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">enabled</span><span class="p">&gt;</span><span class="k">true</span><span class="p">&lt;/</span><span class="n">enabled</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">updatePolicy</span><span class="p">&gt;</span><span class="n">never</span><span class="p">&lt;/</span><span class="n">updatePolicy</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="n">releases</span><span class="p">&gt;</span>
    <span class="p">&lt;/</span><span class="n">pluginRepository</span><span class="p">&gt;</span>
    <span class="p">&lt;/</span><span class="n">pluginRepositories</span><span class="p">&gt;</span>

    <span class="p">&lt;</span><span class="n">repositories</span><span class="p">&gt;</span>
        <span class="p">&lt;</span><span class="n">repository</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">id</span><span class="p">&gt;</span><span class="n">central</span><span class="p">&lt;/</span><span class="n">id</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">name</span><span class="p">&gt;</span><span class="n">Central</span> <span class="n">Repository</span><span class="p">&lt;/</span><span class="n">name</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">url</span><span class="p">&gt;</span><span class="n">http</span><span class="p">:</span><span class="c1">//repo.maven.apache.org/maven2&lt;/url&gt;</span>
            <span class="p">&lt;</span><span class="n">layout</span><span class="p">&gt;</span><span class="k">default</span><span class="p">&lt;/</span><span class="n">layout</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">snapshots</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">enabled</span><span class="p">&gt;</span><span class="k">false</span><span class="p">&lt;/</span><span class="n">enabled</span><span class="p">&gt;</span>
            <span class="p">&lt;/</span><span class="n">snapshots</span><span class="p">&gt;</span>
            <span class="p">&lt;</span><span class="n">releases</span><span class="p">&gt;</span>
                <span class="p">&lt;</span><span class="n">enabled</span><span class="p">&gt;</span><span class="k">true</span><span class="p">&lt;/</span><span class="n">enabled</span><span class="p">&gt;</span>
            <span class="p">&lt;/</span><span class="n">releases</span><span class="p">&gt;</span>
        <span class="p">&lt;/</span><span class="n">repository</span><span class="p">&gt;</span>
    <span class="p">&lt;/</span><span class="n">repositories</span><span class="p">&gt;</span>
</pre></div>
<p>You may now have to import all the dependencies we&#39;ve just added.  You can do this in IntelliJ by pressing <em>Ctrl-Shift-A</em> to bring up the Action window, then typing <em>reimport</em> and selecting <em>Reimport All Maven Projects</em>:</p>

<p><img alt="Silvrback blog image" src="https://silvrback.s3.amazonaws.com/uploads/affa3953-1971-44af-adef-7dc129d3affe/reimportDependencies_large.jpg" /></p>

<p>That&#39;s it for Part 1 - We&#39;re now ready to start modelling some pages and creating some tests!</p>

<p>Download the project for part 1 on GitHub if you prefer:  <a href="https://github.com/rushby/geb-example-project-part1">https://github.com/rushby/geb-example-project-part1</a></p>
]]></content:encoded>
      </item>
      <item>
        <guid>http://rushby.com/getting-started-selenium-automation-with-SpecFlow-PageObject#22067</guid>
          <pubDate>Thu, 11 Feb 2016 12:40:36 +0000</pubDate>
        <link>http://rushby.com/getting-started-selenium-automation-with-SpecFlow-PageObject</link>
        <title>Getting Started: Selenium Automation C#</title>
        <description>Object Oriented UI tests using Page Objects and SpecFlow</description>
        <content:encoded><![CDATA[<p>There&#39;s plenty of guides online describing what Selenium does and how to get up and running with Visual Studio and SpecFlow - so I won&#39;t go into too much detail here.  I want to focus on maintainability and reusability.  I&#39;ve stayed away from using any of the Selenium wrappers for this post, and will be blogging about those in the future.</p>

<p>Start by doing the following:</p>

<ul>
<li>Create a new Class Library Project</li>
<li>Add the SpecFlow extension to Visual Studio</li>
<li><p>Install the following via NuGet:</p>

<p>-Selenium.WebDriver<br>
    -Selenium.Support<br>
-WebDriver.ChromeDriver <br>
-SpecFlow.NUnit<br>
    -SpecRun.SpecFlow</p></li>
</ul>

<p>Your App.Config should look something like this:</p>
<div class="highlight"><pre><span></span><span class="cp">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
<span class="nt">&lt;configuration&gt;</span>
  <span class="nt">&lt;configSections&gt;</span>
    <span class="nt">&lt;section</span> <span class="na">name=</span><span class="s">&quot;specFlow&quot;</span> <span class="na">type=</span><span class="s">&quot;TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow&quot;</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/configSections&gt;</span>
  <span class="nt">&lt;specFlow&gt;</span>
    <span class="nt">&lt;unitTestProvider</span> <span class="na">name=</span><span class="s">&quot;SpecRun+NUnit&quot;</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;plugins&gt;</span>
      <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">&quot;SpecRun&quot;</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/plugins&gt;</span>
<span class="nt">&lt;/specFlow&gt;</span>
<span class="nt">&lt;/configuration&gt;</span>
</pre></div>
<p>Add the ChromeDriver.exe location to the AppSettings section of the app.config - other browser drivers would be added in the same way, so we only edit one place if we need to change the location:</p>
<div class="highlight"><pre><span></span>  <span class="nt">&lt;appSettings&gt;</span>
    <span class="nt">&lt;add</span> <span class="na">key=</span><span class="s">&quot;chromeDriver&quot;</span> <span class="na">value=</span><span class="s">&quot;C:\Users\Administrator\Documents&quot;</span><span class="nt">/&gt;</span>
  <span class="nt">&lt;/appSettings&gt;</span>
</pre></div>
<h3 id="specflow-attributes">SpecFlow Attributes</h3>

<p>Adding the <em>[Binding]</em> attribute to a class lets SpecFlow know that the class contains Step Definitions.  This attribute needs to be on every class that contains code required for the tests to execute correctly.</p>

<p>SpecFlow has a number of attributes or &quot;hooks&quot; that can be used to decorate methods, these allow for methods to be called at certain times.  For instances methods decorated with the <em>[BeforeScenario]</em> and <em>[AfterScenario]</em> attributes would be called before and after the scenario has executed. </p>

<p>Multiple attributes of the same name are executed in an unpredictable order, to get around this you can set an order similar to <em>[BeforeScenario(Order=1)]</em>.</p>

<p>Attributes can also support tag filtering, meaning only scenarios that are prefixed with an <em>@mytagname</em> in the Feature file will run the decorated method <em>[AfterScenario(&quot;mytagname&quot;)]</em>.</p>

<p>More detail on SpecFlow attributes can be found <a href="https://github.com/techtalk/SpecFlow/wiki/Hooks">HERE</a>.</p>

<h3 id="test-setup">Test Setup</h3>

<p>Create a test setup base class - I call mine TestSetup.  This class is used in conjunction with a number of SpecFlow&#39;s attributes to initialise the browser before the test begins and perform any tasks at the end of the scenario, such as disposing the browser, calling code to take a screenshot  if the test failed, and setting the database back to its original state at the end of the test.</p>
<div class="highlight"><pre><span></span>    <span class="k">public</span> <span class="k">class</span> <span class="nc">TestSetup</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="k">static</span> <span class="n">IWebDriver</span> <span class="n">Browser</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

<span class="na">        [BeforeScenario]</span>
        <span class="k">private</span> <span class="k">void</span> <span class="nf">InitialiseScenario</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="k">try</span>
            <span class="p">{</span>
                <span class="kt">var</span> <span class="n">options</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ChromeOptions</span> <span class="p">{</span><span class="n">BinaryLocation</span> <span class="p">=</span> <span class="s">@&quot;C:\Google\Application\chrome.exe&quot;</span><span class="p">};</span>
            <span class="n">Browser</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ChromeDriver</span><span class="p">(</span><span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[</span><span class="s">&quot;chromeDriver&quot;</span><span class="p">],</span> <span class="n">options</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">throw</span> <span class="k">new</span> <span class="nf">Exception</span><span class="p">(</span><span class="s">&quot;Unable to locate chrome driver - check the App.config to   ensure the directory is correct for chromeDriver!&quot;</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>

<span class="na">        [AfterScenario]</span>
        <span class="k">private</span> <span class="k">void</span> <span class="nf">TearDownScenario</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="n">Browser</span><span class="p">.</span><span class="n">Dispose</span><span class="p">();</span>
        <span class="p">}</span>

<span class="na">        [AfterScenario]</span>
        <span class="k">private</span> <span class="k">void</span> <span class="nf">ShowErrors</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">ScenarioContext</span><span class="p">.</span><span class="n">Current</span><span class="p">.</span><span class="n">TestError</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="c1">//ToDo Add some code to capture screenshot.</span>
            <span class="p">}</span>
        <span class="p">}</span>

<span class="na">        [BeforeScenario(&quot;resetDatabase&quot;)]</span>
<span class="na">        [AfterScenario(&quot;resetDatabase&quot;)]</span>
        <span class="k">private</span> <span class="k">void</span> <span class="nf">ResetDatabase</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="c1">//ToDo run SQL script to put database in original state.</span>
        <span class="p">}</span>
    <span class="p">}</span>
</pre></div>
<p><em>Note:  The [Binding] attribute is not required on the TestSetup class as we are going to inherit it.  The derived class will have the [Binding] attribute, if both have it you may find 2 browser instances are created each time you run the tests</em></p>

<p>The <em>IWebDriver</em> property is the WebDriver interface which controls the browser and allows you to interact with elements on the page.  You will also notice that the <em>InitialiseScenario()</em> method assigns this interface to a new <em>ChromeDriver</em> instance, which utilises the <em>App.Config</em> setting we previously set up.  Any change to driver type would be made here (as additional app settings in the config).</p>

<p>We will come back to this base class once we create the Page Objects.</p>

<h3 id="page-objects">Page Objects</h3>

<p>Using Page Objects allows you to separate the implementation from the specification - this makes your tests less brittle and easier to read.  A Page Object represents a web page (or part of a web page) and by utilising a Page Object you can place all the logic required to interact with part of a web page into a single location, improving maintainability.</p>

<p>The Page Object encapsulates all the logic surrounding page interactions, allowing your tests to concentrate on <em>what to do</em> rather than <em>how to do it</em>.</p>

<p>For this example we will use Wikipedia.com.  I&#39;ve added the default url into the App.config as follows(under the chromeDriver setting I added earlier):</p>
<div class="highlight"><pre><span></span>    <span class="nt">&lt;add</span> <span class="na">key=</span><span class="s">&quot;MainPageUrl&quot;</span> <span class="na">value=</span><span class="s">&quot;https://www.wikipedia.org/&quot;</span><span class="nt">/&gt;</span>
</pre></div>
<p>Begin by creating an abstract class, I call it PageObject.  This class will contain common web page properties such as its Title and URL.  This class can also contain methods to fill out all fields with values detailed in the test, or with default values for each field on the page - useful to progress through a multi page website, and also move most form filling actions into a single method containing a switch statement to decide how each field is selected (I&#39;ll blog about this in the future).</p>

<p>For now I&#39;ve created the following:</p>
<div class="highlight"><pre><span></span>    <span class="k">public</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">PageObject</span>
    <span class="p">{</span>
        <span class="k">internal</span> <span class="kt">string</span> <span class="n">Title</span>
        <span class="p">{</span>
            <span class="k">get</span> <span class="p">{</span> <span class="k">return</span> <span class="n">Browser</span><span class="p">.</span><span class="n">Title</span><span class="p">;</span> <span class="p">}</span>
        <span class="p">}</span>

        <span class="k">internal</span> <span class="k">static</span> <span class="kt">string</span> <span class="n">Url</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
        <span class="k">protected</span> <span class="k">static</span> <span class="n">IWebDriver</span> <span class="n">Browser</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

        <span class="k">protected</span> <span class="nf">PageObject</span><span class="p">(</span><span class="n">IWebDriver</span> <span class="n">driver</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">Url</span> <span class="p">=</span> <span class="n">ConfigurationManager</span><span class="p">.</span><span class="n">AppSettings</span><span class="p">[(</span><span class="n">GetType</span><span class="p">().</span><span class="n">Name</span><span class="p">)</span> <span class="p">+</span> <span class="s">&quot;Url&quot;</span><span class="p">];</span>
            <span class="n">Browser</span> <span class="p">=</span> <span class="n">driver</span><span class="p">;</span>
            <span class="n">GotoPageUrl</span><span class="p">();</span>
        <span class="p">}</span>

        <span class="k">public</span> <span class="k">void</span> <span class="nf">GotoPageUrl</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="k">try</span>
            <span class="p">{</span>
                <span class="n">Browser</span><span class="p">.</span><span class="n">Navigate</span><span class="p">().</span><span class="n">GoToUrl</span><span class="p">(</span><span class="n">Url</span><span class="p">);</span>
            <span class="p">}</span>
            <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">e</span><span class="p">)</span>
            <span class="p">{</span>
                <span class="k">throw</span> <span class="k">new</span> <span class="nf">Exception</span><span class="p">(</span><span class="n">GetType</span><span class="p">().</span><span class="n">Name</span> <span class="p">+</span> <span class="s">&quot; could not be loaded. Check page url is correct in app.config.&quot;</span> <span class="p">+</span>
                                    <span class="s">&quot; &quot;</span> <span class="p">+</span> <span class="n">e</span><span class="p">.</span><span class="n">Message</span><span class="p">);</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
</pre></div>
<p><em>NOTE:   you may need to add a reference to System.configuration.dll if it&#39;s not added automatically</em></p>

<p>This class retrieves the relevant page URL from the App.config using <em>(GetType().Name) + &quot;Url&quot;</em> so if we have an inheriting class called MainPage, GetType().Name will retrieve the class name as a String and the code then concatenates this class name and &quot;Url&quot; to become <em>MainPageUrl</em>.  This then matches the app setting we just added to the App.Config.</p>

<p>Next I create a Page Object to represent the Wikipedia main page, called MainPage, which inherits from PageObject:</p>
<div class="highlight"><pre><span></span>    <span class="k">public</span> <span class="k">class</span> <span class="nc">MainPage</span> <span class="p">:</span> <span class="n">PageObject</span>
    <span class="p">{</span>
        <span class="k">public</span> <span class="nf">MainPage</span><span class="p">(</span><span class="n">IWebDriver</span> <span class="n">driver</span><span class="p">)</span> <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">driver</span><span class="p">)</span>
        <span class="p">{</span>

        <span class="p">}</span>
    <span class="p">}</span>
</pre></div>
<p>Notice that the MainPage constructor passes the WebDriver instance to its base PageObject which will in turn navigate the browser to the pages Url.</p>

<h3 id="iwebelement-findsby">IWebElement &amp; FindsBy</h3>

<p>Now I&#39;ve created a Page Object to represent the Wikipedia main page I need to add the elements (fields, buttons, etc.) as properties.  This is achieved by firstly adding an appropriately named IWebElement property to the MainPage class:</p>
<div class="highlight"><pre><span></span><span class="k">private</span> <span class="n">IWebElement</span> <span class="n">_searchField</span><span class="p">;</span>
</pre></div>
<p>I then decorate the property with the FindsBy attribute.  This attribute is part of the OpenQA.Selenium.Support.PageObjects namespace and allows an element to be located on the web page by a number of means including Id, CssSelector, ClassName or Xpath and assigned to the property.  You can also create a custom method if required.</p>
<div class="highlight"><pre><span></span><span class="na">[FindsBy(How = How.Id, Using = &quot;searchInput&quot;)]</span>
 <span class="k">private</span> <span class="n">IWebElement</span> <span class="n">_searchField</span><span class="p">;</span>
</pre></div>
<p>For this example I will use only 2 elements on the page, so I&#39;ve added a second property for the search button:</p>
<div class="highlight"><pre><span></span><span class="na">[FindsBy(How = How.Name, Using = &quot;go&quot;)]</span>
 <span class="k">private</span> <span class="n">IWebElement</span> <span class="n">_searchButton</span><span class="p">;</span>
</pre></div>
<p>In reality your web page will have many elements, your Page Objects might then represent sections of the page rather than whole pages in order to improve maintainability.</p>

<p>Now we need 2 methods, one to enter text into the Search field and one to click the Search button:</p>
<div class="highlight"><pre><span></span><span class="k">public</span> <span class="k">void</span> <span class="nf">EnterSearchText</span><span class="p">(</span><span class="kt">string</span> <span class="n">searchText</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">_searchField</span><span class="p">.</span><span class="n">SendKeys</span><span class="p">(</span><span class="n">searchText</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">public</span> <span class="k">void</span> <span class="nf">ClickSearchButton</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">_searchButton</span><span class="p">.</span><span class="n">Click</span><span class="p">();</span>
<span class="p">}</span>
</pre></div>
<p>Again for this example I&#39;ll keep it simple and add these methods to the MainPage object, but once you start creating additional Page Objects you will want to pull this common functionality out, possibly into the base PageObject class, for reusability and maintainability.  This will be covered in the next blog post.</p>

<h3 id="specflow-feature-file-scenario">SpecFlow Feature File &amp; Scenario</h3>

<p>The next step is to add a Feature file to the project and add a new Scenario:</p>
<div class="highlight"><pre><span></span><span class="k">Feature:</span><span class="nf"> MainPage</span>
<span class="nf">    In order to further my test automation knowledge</span>
<span class="nf">    As an automation tester</span>
<span class="nf">    I want to search for information on Wikipedia</span>

<span class="k">Scenario:</span><span class="nf"> Search for Test Automation on Wikipedia</span>
<span class="k">    Given </span><span class="nf">I am on the main Wikipedia page</span>
<span class="nf">    </span><span class="k">And </span><span class="nf">I enter Test Automation into the Search field</span>
<span class="nf">    </span><span class="k">When </span><span class="nf">I click the Search button</span>
<span class="nf">    </span><span class="k">Then </span><span class="nf">the Test automation wikipedia page is displayed</span>
</pre></div>
<p>Right click the scenario text and select Generate Step Definitions, you can now either copy the methods to clipboard and paste them into your own class (make sure you add the <em>[Binding]</em> attribute to the class) or click the Generate button .  This will create a new class (mine is called MainPageSteps.cs) that contains the following:</p>
<div class="highlight"><pre><span></span><span class="nf">        [Given(</span><span class="nt">@&quot;I</span><span class="nf"> am on the main Wikipedia page&quot;</span><span class="s">)]</span>
<span class="s">        public void GivenIAmOnTheMainWikipediaPage()</span>
<span class="s">        {</span>
<span class="s">            ScenarioContext.Current.Pending();</span>
<span class="s">        }</span>

<span class="s">        [Given(@</span><span class="nf">&quot;I enter Test Automation into the Search field&quot;</span><span class="s">)]</span>
<span class="s">        public void GivenIEnterTestAutomationIntoTheSearchField()</span>
<span class="s">        {</span>
<span class="s">            ScenarioContext.Current.Pending();</span>
<span class="s">        }</span>

<span class="s">        [When(@</span><span class="nf">&quot;I click the Search button&quot;</span><span class="s">)]</span>
<span class="s">        public void WhenIClickTheSearchButton()</span>
<span class="s">        {</span>
<span class="s">            ScenarioContext.Current.Pending();</span>
<span class="s">        }</span>

<span class="s">        [Then(@</span><span class="nf">&quot;the Test Automation wikipedia page is displayed&quot;</span><span class="s">)]</span>
<span class="s">        public void ThenTheTestAutomationWikipediaPageIsDisplayed()</span>
<span class="s">        {</span>
<span class="s">            ScenarioContext.Current.Pending();</span>
<span class="s">        }</span>
</pre></div>
<p>I can now make some changes to the methods which should allow reuse in the future:</p>
<div class="highlight"><pre><span></span><span class="nf"> [Given(</span><span class="nt">@&quot;I</span><span class="nf"> am on the main Wikipedia page&quot;</span><span class="s">)]</span>
<span class="s">        public void GivenIAmOnTheMainWikipediaPage()</span>
<span class="s">        {</span>
<span class="s">            ScenarioContext.Current.Pending();</span>
<span class="s">        }</span>

<span class="s">        [Given(@</span><span class="nf">&quot;I enter (.*) into the Search field&quot;</span><span class="s">)]</span>
<span class="s">        public void GivenIEnterTestAutomationIntoTheSearchField(string input)</span>
<span class="s">        {</span>
<span class="s">            ScenarioContext.Current.Pending();</span>
<span class="s">        }</span>

<span class="s">        [When(@</span><span class="nf">&quot;I click the (.*) button&quot;</span><span class="s">)]</span>
<span class="s">        public void WhenIClickTheSearchButton(string butt)</span>
<span class="s">        {</span>
<span class="s">            ScenarioContext.Current.Pending();</span>
<span class="s">        }</span>

<span class="s">        [Then(@</span><span class="nf">&quot;the (.*) wikipedia page is displayed&quot;</span><span class="s">)]</span>
<span class="s">        public void ThenTheTestAutomationWikipediaPageIsDisplayed(string page)</span>
<span class="s">        {</span>
<span class="s">            ScenarioContext.Current.Pending();</span>
<span class="s">        }</span>
</pre></div>
<p>The wildcards added mean as long as the Given, When or Then statement wording matches then the (.*) will be taken as an input parameter into the method.</p>

<p>Now to finish off the Scenario all the ScenarioContext.Current.Pending() lines are replaced with actual logic to perform the test and your class should look like this:</p>
<div class="highlight"><pre><span></span><span class="na">    [Binding]</span>
    <span class="k">public</span> <span class="k">class</span> <span class="nc">MainPageSteps</span> <span class="p">:</span> <span class="n">TestSetup</span>
    <span class="p">{</span>
        <span class="k">private</span> <span class="n">MainPage</span> <span class="n">PageToTest</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>

<span class="na">        [Given(@&quot;I am on the main Wikipedia page&quot;)]</span>
        <span class="k">public</span> <span class="k">void</span> <span class="nf">GivenIAmOnTheMainWikipediaPage</span><span class="p">()</span>
        <span class="p">{</span>
            <span class="n">PageToTest</span> <span class="p">=</span> <span class="k">new</span> <span class="n">MainPage</span><span class="p">(</span><span class="n">Browser</span><span class="p">);</span>
        <span class="p">}</span>

<span class="na">        [Given(@&quot;I enter (.*) into the Search field&quot;)]</span>
        <span class="k">public</span> <span class="k">void</span> <span class="nf">GivenIEnterTestAutomationIntoTheSearchField</span><span class="p">(</span><span class="kt">string</span> <span class="n">input</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">PageToTest</span><span class="p">.</span><span class="n">EnterSearchText</span><span class="p">(</span><span class="n">input</span><span class="p">);</span>
        <span class="p">}</span>

<span class="na">        [When(@&quot;I click the (.*) button&quot;)]</span>
        <span class="k">public</span> <span class="k">void</span> <span class="nf">WhenIClickTheSearchButton</span><span class="p">(</span><span class="kt">string</span> <span class="n">butt</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">PageToTest</span><span class="p">.</span><span class="n">ClickSearchButton</span><span class="p">();</span>
        <span class="p">}</span>

<span class="na">        [Then(@&quot;the (.*) wikipedia page is displayed&quot;)]</span>
        <span class="k">public</span> <span class="k">void</span> <span class="nf">ThenTheTestAutomationWikipediaPageIsDisplayed</span><span class="p">(</span><span class="kt">string</span> <span class="n">page</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="n">Assert</span><span class="p">.</span><span class="n">AreEqual</span><span class="p">(</span><span class="n">page</span> <span class="p">+</span> <span class="s">&quot; - Wikipedia, the free encyclopedia&quot;</span><span class="p">,</span> <span class="n">PageToTest</span><span class="p">.</span><span class="n">Title</span><span class="p">);</span>
        <span class="p">}</span>
</pre></div>
<p>That&#39;s it for now, these tests should run by right clicking within the Feature file and selecting &quot;Run SpecFlow Scenarios&quot;.  In my next blog post i&#39;ll reuse this code, refactor further and implement a Selenium wrapper called Coypu.</p>

<p>I&#39;ll be uploading the source code over the weekend for anyone who&#39;s interested and will provide a link here. </p>
]]></content:encoded>
      </item>
      <item>
        <guid>http://rushby.com/acceptance-criteria#19840</guid>
          <pubDate>Sat, 21 Nov 2015 13:55:08 +0000</pubDate>
        <link>http://rushby.com/acceptance-criteria</link>
        <title>Acceptance Criteria</title>
        <description>A BDD Guide</description>
        <content:encoded><![CDATA[<p>Well thought out Acceptance Criteria define the boundaries and parameters of a User Story / Feature and allow both the development team and the stakeholder to determine when a story has been completed.</p>

<p>The creation of Acceptance Criteria should be a collaborative approach between the development team and the business, utilising a common language.  Too often language used by the business and that used by development teams and found within code differ and lead to confusion/misinterpretation of requirements.  Acceptance Criteria can help bridge this divide.</p>

<p>Acceptance Criteria should include both functional and non-functional criteria.  Non-functional requirements such as performance, usability and security criteria may not be defined by the stakeholder and as such the initial Acceptance Criteria will be enhanced by the development teams before being signed off by the stakeholder.</p>

<p>The language used during the creation of Acceptance Criteria also becomes important if you are creating automated tests using a BDD tool such as SpecFlow.  Not only must you use the Given-When-Then gherkin syntax you also need to consider reusability, carefully wording steps so that the code behind can be reused.</p>

<p>For instance generating the step definitions in SpecFlow for the step <em>&quot;When I click the Submit button&quot;</em> will produce a method like so:</p>
<div class="highlight"><pre><span></span><span class="na">[When(@&quot;I click the Submit button&quot;)]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">WhenIClickTheSubmitButton</span><span class="p">()</span>
<span class="p">{</span>
     <span class="c1">//Some code.</span>
<span class="p">}</span>
</pre></div>
<p>As clicking buttons is a common step you would then want to make this reusable by replacing the button name with a wildcard, also changing the method name to be more generic:</p>
<div class="highlight"><pre><span></span><span class="na">[When(@&quot;I click the (.*) button&quot;)]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">WhenIClickAButton</span><span class="p">()</span>
<span class="p">{</span>
      <span class="c1">//Some code.</span>
<span class="p">}</span>
</pre></div>
<p>This method is now reusable, but only if you ensure the Acceptance Criteria uses the same language.  This is where reviews should take place to spot issues such as using<br>
<em>&quot;When I click on the Cancel button&quot;</em> rather than <em>&quot;When I click the Cancel button&quot;</em>.  As it stands those two sentences would generate two different methods (Step Definitions) because one contains the word <em>&quot;on&quot;</em> thus creating two identical tests with the only difference being the wording.</p>

<p>Note:  You can combine  criteria that are worded slightly differently, but ask yourself if it&#39;s truly necessary...</p>
<div class="highlight"><pre><span></span><span class="na">[When(@&quot;I click the (.*) button&quot;)]</span>
<span class="na">[When(@&quot;I click on the (.*) button&quot;)]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">WhenIClickAButton</span><span class="p">()</span>
<span class="p">{</span>
      <span class="c1">//Some code.</span>
<span class="p">}</span>   
</pre></div>
<p>Here&#39;s a few pieces of guidance when taking a BDD approach with Acceptance Criteria and SpecFlow:</p>

<p><strong>Acceptance criteria should be written in the 1st person</strong><br>
Write it as if the person using the system is stating what happens:</p>
<div class="highlight"><pre><span></span><span class="k">When </span><span class="nf">I click the Search button</span>
<span class="k">Then </span><span class="nf">I see the Search Results screen.</span>
</pre></div>
<p><strong>There are four possible components to an acceptance test</strong><br>
 These are all mandatory except the &#39;Given&#39; line:</p>

<p><em>Scenario (or Scenario Outline):</em> Describes the test<br>
<em>Given:</em> Describes any preconditions that would allow you to start the test from a particular point<br>
<em>When:</em> Describes the action to be tested<br>
<em>Then:</em> Describes the expected outcome</p>

<p>Each of the sections (Given, When, Then) can be enhanced using the keywords <em>And</em> and <em>But</em>.</p>
<div class="highlight"><pre><span></span><span class="k">Given </span><span class="nf">I am on the Search screen</span>
<span class="k">And </span><span class="nf">I have entered &quot;</span><span class="s">lolcat</span><span class="nf">&quot;into the Search field</span>
<span class="k">When </span><span class="nf">I click the Search button</span>
<span class="k">Then </span><span class="nf">I see search results related to my search</span>
<span class="k">And </span><span class="nf">the first result is “whatever”</span>
</pre></div>
<p><em>But</em> and <em>And</em> are interchangeable in terms of functionality. </p>
<div class="highlight"><pre><span></span><span class="k">Given </span><span class="nf">I have searched for &quot;</span><span class="s">cats</span><span class="nf">&quot;</span>
<span class="k">But </span><span class="nf">there are no results</span>
</pre></div>
<p>…will have the same effect as</p>
<div class="highlight"><pre><span></span><span class="k">Given </span><span class="nf">I have searched for &quot;</span><span class="s">cats</span><span class="nf">&quot;</span>
<span class="k">And </span><span class="nf">there are no results</span>
</pre></div>
<p>There will obviously be times where one makes more sense than the other.</p>

<p><strong>Use consistent screen names</strong> <br>
 To enable test re-use and to avoid confusion, screens should be referenced in the same way throughout the acceptance criteria and should be specific to the app where necessary.  However, you need to check this with your developers, as common test code may have been written which can be reused across different apps.</p>

<p>An Acceptance Criteria dictionary which for instance contains reusable names for commonly-referenced screens and controls is definitely a useful resource for the entire team.</p>

<p><strong>Use consistent wording</strong><br>
To enable test re-use and to avoid confusion, common actions should be worded in the same way. E.g. instead of sometimes writing <em>When I press “next”</em> and other times writing <em>When I click ‘Next’</em> or <em>When the NEXT button is clicked</em> or <em>When I press the Next button</em> you should pick one and let the team know what you&#39;ve decided so that a consistent approach can be used throughout the tests (consider adding this to your Acceptance Criteria dictionary).</p>

<p><strong>Know the difference between single quotes and double quotes.</strong><br>
Whenever words are surrounded by double quotes they are interpreted as inputs to the test. For instance:</p>
<div class="highlight"><pre><span></span><span class="k">When </span><span class="nf">I click &quot;</span><span class="s">Next</span><span class="nf">&quot;</span>
<span class="k">When </span><span class="nf">I click &quot;</span><span class="s">Back</span><span class="nf">&quot;</span>
</pre></div>
<p>Behind the scenes this is just one WhenIClick test, which will have different values (&quot;Back&quot; or &quot;Next&quot;) passed into it. However, single quotes are ignored and can therefore be used for emphasis.</p>

<p><strong>Impact Analysis: Always review the relevant acceptance tests that already exist</strong><br>
As with any type of test some may need to be updated, such as when writing acceptance criteria for changes to a screen that already exists (rather than a new screen). If you&#39;re developing iteratively you should expect many changes to the software and the tests.</p>

<p><strong>Review the initial draft of the Acceptance Criteria</strong><br>
Developers and Testers should review the criteria as the developer sometimes needs to make small tweaks to the acceptance criteria for code purposes, and the tester may think of scenarios you have not considered.  These changes should then be agreed by the stakeholder.</p>

<p><strong>The concept of “or” does not exist.</strong><br>
You cannot say “When I click A or B, Then…”<br>
In fact, this is two tests:</p>

<p>“When I click A, Then…”<br>
“When I click B, Then…”</p>

<p>However, you may well be able to use a Scenario Outline.</p>

<p><strong>Know when to use Scenario Outlines and when to use table parameters</strong><br>
<em>Scenario Outlines</em> allow the same test to be run repeatedly but with different data each time.  For instance, you may want to visit the same page several times, and each time select a different item from a dropdown:</p>
<div class="highlight"><pre><span></span><span class="k">Scenario Outline:</span><span class="nf"> As a customer I can add differing amounts of the same item to my shopping basket</span>
<span class="k"> Given </span><span class="nf">I am on the ‘Product’ screen</span>
<span class="nf"> </span><span class="k">When </span><span class="nf">I select </span><span class="nv">&lt;number of items&gt;</span><span class="nf"> from the Quantity dropdown for </span><span class="nv">&lt;product&gt;</span><span class="nf"></span>
<span class="nf"> </span><span class="k">Then </span><span class="nv">&lt;product&gt;</span><span class="nf"> is added to my basket with a quantity of </span><span class="nv">&lt;number of items&gt;</span><span class="nf"></span>
<span class="nf"> </span><span class="k">Examples:</span>
<span class="k"> |</span><span class="nv"> product</span><span class="k">|</span><span class="nv"> number of items</span><span class="k"> |</span><span class="nf"></span>
<span class="k"> |</span><span class="s"> cake</span><span class="k"> |</span><span class="s"> 2</span><span class="k"> |</span><span class="nf"></span>
<span class="k"> |</span><span class="s"> game</span><span class="k"> |</span><span class="s"> 1</span><span class="k"> |</span>
</pre></div>
<p><em>Table Parameters</em> allow several pieces of data to be passed to one test.  For example, you may want to visit one page and enter several different pieces of invalid data into the various inputs. These can all be entered into the same page. If you used a Scenario Outline for this, you would end up visiting the same page several times (possibly via a complicated and lengthy flow) when you could get away with visiting it once:</p>
<div class="highlight"><pre><span></span><span class="k">Scenario:</span><span class="nf"> If I attempt to pay without completing a required field I am shown a validation error</span>
<span class="k">Given </span><span class="nf">I am on the Payment screen</span>
<span class="k">And </span><span class="nf">I click the Next button without filling in any details</span>
<span class="k">Then </span><span class="nf">I see the following errors</span>
<span class="nf">| fieldLabel</span><span class="k">           |</span><span class="s"> errorMessage</span><span class="k">                          |</span><span class="nf"></span>
<span class="nf">| Card Number</span><span class="k">          |</span><span class="s"> You need to provide a card number</span><span class="k">     |</span><span class="nf"></span>
<span class="nf">| Cardholder Name</span><span class="k">      |</span><span class="s"> You need to provide a name</span><span class="k">            |</span><span class="nf"></span>
<span class="nf">| Card Security Number</span><span class="k"> |</span><span class="s"> You need to provide a security number</span><span class="k"> |</span>
</pre></div>
<p><em>Multiple Parameters</em> are a lot like table parameters, but are written instead using a colon and a comma-separated list of values enclosed in straight quotes:</p>
<div class="highlight"><pre><span></span><span class="k">Scenario:</span><span class="nf"> As a customer I see the Payment Failure screen when payment is unsuccessful</span>
<span class="k">When </span><span class="nf">I visit the Payment Failure screen</span>
<span class="k">Then </span><span class="nf">I see the following options: &quot;</span><span class="s">Try again</span><span class="nf">&quot;, &quot;</span><span class="s">Edit card details</span><span class="nf">&quot;, &quot;</span><span class="s">Choose different payment option</span><span class="nf">&quot;</span>
</pre></div>]]></content:encoded>
      </item>
  </channel>
</rss>