<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Juho Perälä</title>
    <description>The latest articles on DEV Community by Juho Perälä (@juperala).</description>
    <link>https://dev.to/juperala</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F20654%2F6aea9aeb-e3ba-42c8-9ac9-23e431b206a5.jpg</url>
      <title>DEV Community: Juho Perälä</title>
      <link>https://dev.to/juperala</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/juperala"/>
    <language>en</language>
    <item>
      <title>Make side projects that matter</title>
      <dc:creator>Juho Perälä</dc:creator>
      <pubDate>Tue, 12 Jan 2021 07:01:16 +0000</pubDate>
      <link>https://dev.to/juperala/make-side-projects-that-matter-2en5</link>
      <guid>https://dev.to/juperala/make-side-projects-that-matter-2en5</guid>
      <description>&lt;p&gt;For me learning tech and new skill is not just for having 9-5 work and paying the bills. I have always liked to have side projects. As far as I can remember I have always tinkered something on the side of my day job. When it was learning new language or framework like React, testing tool like Cypress or dabbling with Raspberry Pi, Arduino or some other gadget of interest.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tech or Content First?
&lt;/h1&gt;

&lt;p&gt;For me the side projects have always started tech first, from the interest to learn some new tool or technology. That is totally fine for learning and applying the learned skills in real world example. But it has also meant that the developed side projects have been dispensable. I mean like fire and forget that - once finished - have been doomed to die. There has been no motivation to keep the projects up and running afterwards. &lt;/p&gt;

&lt;p&gt;This was before my last side project that I started about an year a go. I wanted to make a larger side project where I could really learn and apply my skills from every aspect of developing an online product and presence.&lt;/p&gt;

&lt;p&gt;To keep my interest on the project I chose the topic to be inline with my other hobbies. As I had been watch enthusiast for several years by then I deciced to start an wristwatch media site dedicated for watch enthusiasts and others interested about wristwatches.&lt;/p&gt;

&lt;p&gt;I named the project as &lt;em&gt;Ranteessa&lt;/em&gt; ('&lt;em&gt;On the Wrist&lt;/em&gt;' in English) and it consist of the actual &lt;a href="https://ranteessa.fi"&gt;ranteessa.fi&lt;/a&gt; site with associated social media accounts on &lt;a href="https://www.instagram.com/ranteessa/"&gt;Instagram&lt;/a&gt;, &lt;a href="https://youtube.com/c/Ranteessa"&gt;YouTube&lt;/a&gt; and &lt;a href="https://www.facebook.com/ranteessafi/"&gt;Facebook&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Victory
&lt;/h1&gt;

&lt;p&gt;And, oh boy, has this paid off. Instead of going tech firsts to start yet another random project working on a topic actually relevant to you is SO MUCH more rewarding.&lt;/p&gt;

&lt;p&gt;Working with project expanded across multiple platforms and with real subscribers and followers you get the opportunity to learn so much more. Everything from developing and hosting a website to SEO optimization, analytics, social media and marketing. And not just the tech stuff, biggest learning has come with content creation including things like video production, editing, blogging, presentation skills and much more.&lt;/p&gt;

&lt;p&gt;In grand scheme this is still just a miniscule project, but for me it has been a huge victory. As of today blog is getting steadily over thousand unique visitors monthly and both Instagram and YouTube channels have gained around 500 followers. Not bad for a nerdy Finnish speaking channel talking about wristwatches. But by far the biggest value of the project has been learning new skills and connecting with other watch enthusiasts around the Finland.&lt;/p&gt;

&lt;p&gt;Surprisingly the &lt;em&gt;Ranteessa&lt;/em&gt; project has also moved bit of beyond being just a hobby project. It has also started gaining attraction for collaborations with commercial partners and stakeholders. Only time will tell what will this evolve in the future.&lt;/p&gt;

&lt;h1&gt;
  
  
  Passion Rules The Game
&lt;/h1&gt;

&lt;p&gt;When you think about starting your next side project, pick a topic that you are really interested about. Something close to your heart and other hobbies.&lt;/p&gt;

&lt;p&gt;It will pay off, I promise.&lt;/p&gt;

&lt;p&gt;Ps. If you are interested on wristwatches, please feel free to take a look and follow Ranteessa on &lt;a href="https://www.instagram.com/ranteessa/"&gt;Instagram&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>motivation</category>
      <category>writing</category>
      <category>development</category>
    </item>
    <item>
      <title>How to run Robot Framework test from command line?</title>
      <dc:creator>Juho Perälä</dc:creator>
      <pubDate>Thu, 26 Mar 2020 15:48:20 +0000</pubDate>
      <link>https://dev.to/juperala/how-to-run-robot-framework-test-from-command-line-5aa</link>
      <guid>https://dev.to/juperala/how-to-run-robot-framework-test-from-command-line-5aa</guid>
      <description>&lt;p&gt;Yesterday a colleague learning test automation forgot the syntax for running Robot Framework test cases from command-line. Although full command-line syntax is described on the &lt;a href="https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html"&gt;Robot Framework User Guide&lt;/a&gt; it is rather long and tedious document to dive into.&lt;/p&gt;

&lt;p&gt;This post aims to provide quick introduction for executing single, set or all Robot Framework test cases in a project.&lt;/p&gt;

&lt;h1&gt;
  
  
  Basic syntax
&lt;/h1&gt;

&lt;p&gt;The basic syntax for executing Robot Framework tests from command line is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="c"&gt;# basic syntax&lt;/span&gt;
    robot &lt;span class="o"&gt;[&lt;/span&gt;options] robot_files

    &lt;span class="c"&gt;# example with options&lt;/span&gt;
    robot &lt;span class="nt"&gt;-v&lt;/span&gt; URL:http://example.com example.robot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For full list of command-line options see &lt;code&gt;robot --help&lt;/code&gt; or &lt;code&gt;robot -h&lt;/code&gt; option.&lt;/p&gt;

&lt;h1&gt;
  
  
  Execute all test cases in folder(s)
&lt;/h1&gt;

&lt;p&gt;To run all robot tests in the folder (including subfolders) use &lt;code&gt;.&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="c"&gt;# execute all tests in all robot files in current folder and subfolders&lt;/span&gt;
    robot &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Execute all test cases in single file
&lt;/h1&gt;

&lt;p&gt;To run all robot tests in single robot file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="c"&gt;# execute all tests in single robot file in current folder&lt;/span&gt;
    robot example.robot

    &lt;span class="c"&gt;# execute all tests in single robot file in subfolder&lt;/span&gt;
    robot path/to/example.robot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Execute test cases by test name
&lt;/h1&gt;

&lt;p&gt;To run test cases with specific test name use &lt;code&gt;--test&lt;/code&gt; or &lt;code&gt;-t&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="c"&gt;# execute test cases with name "Example" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--test&lt;/span&gt; Example &lt;span class="nb"&gt;.&lt;/span&gt;

    &lt;span class="c"&gt;# execute test cases with name "Example" in specific file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--test&lt;/span&gt; Example example.robot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Also partial test names and patterns can be used with &lt;code&gt;--test&lt;/code&gt; option, see Using partial names and filter patterns.&lt;/p&gt;

&lt;h1&gt;
  
  
  Execute test cases by tags
&lt;/h1&gt;

&lt;p&gt;Test cases and suites annotated with tags (using &lt;code&gt;[Tags]&lt;/code&gt; or &lt;code&gt;Force Tags&lt;/code&gt; syntax) can be executed by selecting tags to be &lt;em&gt;included&lt;/em&gt; or &lt;em&gt;excluded&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Example test suite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    *** Settings *** 
    Force Tags  suite

    *** Test Cases ***
    Test One
        [Tags]  one
        No operation

    Test Two
        [Tags]  two
        No operation
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Also partial tag names and patterns can be used with &lt;code&gt;--include&lt;/code&gt; and &lt;code&gt;--exclude&lt;/code&gt; option, see Using partial names and filter patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Include test cases by tag
&lt;/h2&gt;

&lt;p&gt;To run test cases with specific tag name included use &lt;code&gt;--include&lt;/code&gt; or &lt;code&gt;-i&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="c"&gt;# execute test cases with tag "one" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--include&lt;/span&gt; one &lt;span class="nb"&gt;.&lt;/span&gt;    

    &lt;span class="c"&gt;# execute test cases with tags  "one" and "two" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--include&lt;/span&gt; oneANDtwo &lt;span class="nb"&gt;.&lt;/span&gt;    

    &lt;span class="c"&gt;# execute test cases with tag "one" or "two" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--include&lt;/span&gt; oneORtwo &lt;span class="nb"&gt;.&lt;/span&gt;    

    &lt;span class="c"&gt;# execute test cases with tag "one" but without tag "two" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--include&lt;/span&gt; oneNOTtwo &lt;span class="nb"&gt;.&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Exclude test cases by tag
&lt;/h2&gt;

&lt;p&gt;To run test cases with specific tag name excluded use &lt;code&gt;--exclude&lt;/code&gt; or &lt;code&gt;-e&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="c"&gt;# execute test cases without tag "two" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--exclude&lt;/span&gt; two &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Execute test cases by suite name
&lt;/h1&gt;

&lt;p&gt;In &lt;em&gt;Robot Framework&lt;/em&gt; test folders and &lt;code&gt;.robot&lt;/code&gt; files are considered as test suites.&lt;/p&gt;

&lt;p&gt;Example suite structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;  - +-+- tests
  -   +-+- feature1
  -   | +--- positive.robot
  -   | +--- negative.robot
  -   +-+- feature2
  -     +--- positive.robot
  -     +--- negative.robot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To run test cases in specific test suiteuse &lt;code&gt;--suite&lt;/code&gt; or &lt;code&gt;-s&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="c"&gt;# execute test cases from suites named "positive" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--suite&lt;/span&gt; positive &lt;span class="nb"&gt;.&lt;/span&gt;

    &lt;span class="c"&gt;# execute test cases from suite "feature1\positive" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--suite&lt;/span&gt; feature1.positive &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Also partial suite names and patterns can be used with &lt;code&gt;--suite&lt;/code&gt; option, see Using partial names and filter patterns.&lt;/p&gt;

&lt;h1&gt;
  
  
  Execute failed tests
&lt;/h1&gt;

&lt;p&gt;There is also possibility to rerun all failed test cases and test suites.&lt;/p&gt;

&lt;h2&gt;
  
  
  Execute only failed test cases
&lt;/h2&gt;

&lt;p&gt;To rerun failed test cases use &lt;code&gt;--rerunfailed&lt;/code&gt; or &lt;code&gt;-R&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="c"&gt;# execute test cases failed in previous run (saved in output.xml)&lt;/span&gt;
    robot &lt;span class="nt"&gt;--rerunfailed&lt;/span&gt; output.xml &lt;span class="nb"&gt;.&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Execute failed test suites
&lt;/h2&gt;

&lt;p&gt;To rerun test suites with failed test cases use &lt;code&gt;--rerunfailedsuites&lt;/code&gt; or &lt;code&gt;-S&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="c"&gt;# execute test cases with failed test cases in previous run (saved in output.xml)&lt;/span&gt;
    robot &lt;span class="nt"&gt;--rerunfailedsuites&lt;/span&gt; output.xml &lt;span class="nb"&gt;.&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Using partial names and filter patterns
&lt;/h1&gt;

&lt;p&gt;The presented &lt;code&gt;--test&lt;/code&gt;, &lt;code&gt;--suite&lt;/code&gt;, &lt;code&gt;--include&lt;/code&gt; and &lt;code&gt;--exclude&lt;/code&gt; options also support using partial names and filter patterns to match multiple names and tags:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="c"&gt;# execute test cases containing name "Example" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--test&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;Example&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

    &lt;span class="c"&gt;# execute test cases "Example One" and "Example Two" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--test&lt;/span&gt; &lt;span class="s2"&gt;"Example [One|Two]"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

    &lt;span class="c"&gt;# execute test cases with tags starting with "One" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--include&lt;/span&gt; One&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

    &lt;span class="c"&gt;# execute test cases without tags ending with "Two" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--exclude&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;Two &lt;span class="nb"&gt;.&lt;/span&gt;

    &lt;span class="c"&gt;# execute test cases from suites starting with "positive" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--suite&lt;/span&gt; positive&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For full list of supported filter patterns see User Guide section &lt;a href="https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns"&gt;Simple Patterns&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Combining filters
&lt;/h1&gt;

&lt;p&gt;The presented &lt;code&gt;--test&lt;/code&gt;, &lt;code&gt;--suite&lt;/code&gt;, &lt;code&gt;--include&lt;/code&gt; and &lt;code&gt;--exclude&lt;/code&gt; options can be used also in combination:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    &lt;span class="c"&gt;# execute test cases containing name "Example" and having tag "One" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--include&lt;/span&gt; One &lt;span class="nt"&gt;--test&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;Example&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

    &lt;span class="c"&gt;# execute test cases from suite "FeatureA" exluding tests with tag "Smoke" in any file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--suite&lt;/span&gt; FeatureA &lt;span class="nt"&gt;--exclude&lt;/span&gt; Smoke &lt;span class="nb"&gt;.&lt;/span&gt;

    &lt;span class="c"&gt;# execute test cases with tag "Pending" from specific file.&lt;/span&gt;
    robot &lt;span class="nt"&gt;--exclude&lt;/span&gt; Pending example.robot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>robotframework</category>
      <category>tutorial</category>
      <category>commandlineinterface</category>
    </item>
    <item>
      <title>Review Your Test Automation Code</title>
      <dc:creator>Juho Perälä</dc:creator>
      <pubDate>Wed, 23 Jan 2019 13:46:19 +0000</pubDate>
      <link>https://dev.to/juperala/review-your-test-automation-code-271a</link>
      <guid>https://dev.to/juperala/review-your-test-automation-code-271a</guid>
      <description>&lt;p&gt;Doing test automation is about writing code. Test automation code can be easily treated as second-class citizen. As it's not delivered to customer, development is often less formalized and may lack the scrutiny and quality practices otherwise applied in the organization. It's also often first code many junior developers and testers start their journey into programming.&lt;/p&gt;

&lt;p&gt;However, when it comes to creating valuable and maintainable automation, the automation code should be well implemented with maintainability in mind. Tests should be highly reliable as any false positives, false negatives or test flakiness will break the trusts towards the automation results.&lt;/p&gt;

&lt;p&gt;One way to improve automation quality is to apply code review practices where automated tests are reviewed by your peers. With code review practices you can identify issues in automation that could affect test results and stability.&lt;/p&gt;

&lt;p&gt;This post presents list of possible problem areas in automation code to look for in code reviews.&lt;/p&gt;

&lt;h1&gt;
  
  
  Things to look out in code review
&lt;/h1&gt;

&lt;h2&gt;
  
  
  It's just code
&lt;/h2&gt;

&lt;p&gt;As said, test automation is just code. Therefore common code review guidelines can be applied in the review process. Check out your organization review guidelines and practices if not familiar with doing reviews. For example, common things to look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the code understandable? Is there unnecessary complexity that could be simplified?&lt;/li&gt;
&lt;li&gt;Are functions or classes too big, can those be broken down to smaller parts?&lt;/li&gt;
&lt;li&gt;Does code units have too many responsibilities? Single responsibility principle?&lt;/li&gt;
&lt;li&gt;Does the code follow DRY (Don't Repeat Yourself) pattern? Is there duplication in the code?&lt;/li&gt;
&lt;li&gt;Does the code follow common coding standards and conventions?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Issues specific to test code
&lt;/h2&gt;

&lt;p&gt;In addition of generic code review issues to look for, there are many problem areas and issues in the test logic that can be identified in code reviews. Following chapters describe few common categories of what to look out for.&lt;/p&gt;

&lt;p&gt;The issues are demonstrated with code example using Selenium WebDriver and Java, but the presented issue categories are not specific to any particular language or automation framework per se.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bad assertions
&lt;/h3&gt;

&lt;p&gt;One supprisingly common mistake seen in test scripts is forgotten assersions. Lack of assertion can make your test to produce false positive test results.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;submitIsDisplayed&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="c1"&gt;// check that element is displayed&lt;/span&gt;
        &lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isDisplayed&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;  &lt;span class="c1"&gt;// MISSING ASSERTION&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Retrys
&lt;/h3&gt;

&lt;p&gt;Another issue commonly seen is trying to fix test stability issues by retrying test steps in case of exception. Usually this is a indication of brittle automation code and lack of understanding of the application internal behavior. Identify what is the application behaviour causing test step to fail and create needed wait or missing test logic to handle it reliably.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;inputAmount&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"amount"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StaleElementReferenceException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// INPUT FAILED, RETRYING&lt;/span&gt;
            &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"amount"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sleeps and fixed delays
&lt;/h3&gt;

&lt;p&gt;Very similar to retrys described above are fixed delays (sleeps) commonly seen to fix test stability issues. Identify what is the application event causing test step to fail and create appropriate wait for it. Don't slow down tests with fixed delays.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;acceptCookie&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;InterruptedException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// FIXED DELAY&lt;/span&gt;
        &lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;WebElement&lt;/span&gt; &lt;span class="n"&gt;cookieButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"accept"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;cookieButton&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hard-coded values and configurations
&lt;/h3&gt;

&lt;p&gt;One thing sure is that you never know where your tests will be run in the future. Therefore automation code should be easily configurable. What if you need to test in different environment? With different user? Or with different browser? Make your tests configurable from the get-go by avoiding fixed URLs, drivers, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FirefoxDriver&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// FIXED BROWSER TYPE&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://192.168.1.5/app"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// FIXED URL&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wrong level of abstraction
&lt;/h3&gt;

&lt;p&gt;Commonly seen issue with BDD-based automation is wrong level of abstraction. In BDD the story files and scenarios should serve as examples describing your product behavior without detailed implementation mechanics - allowing common understanding (and means of communication) of product behaviour for different stakeholders.&lt;/p&gt;

&lt;p&gt;Implementation specific scenarios often indicate also that BDD is only created for automation purposes rather than serving as common documentation for the whole development process. As such, having BDD layer in automation is merely just an extra boilerplate to be maintained with no real value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;&lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Application can be started
&lt;span class="nf"&gt;Given &lt;/span&gt;application is opened
&lt;span class="nf"&gt;When &lt;/span&gt;user clicks element &lt;span class="s"&gt;"//button[@title='Start']"&lt;/span&gt; &lt;span class="c"&gt;# SPECIFICS TO UI IMPLEMENTATION&lt;/span&gt;
&lt;span class="nf"&gt;Then &lt;/span&gt;element &lt;span class="s"&gt;"#app &amp;gt; div.started"&lt;/span&gt; is visible        &lt;span class="c"&gt;# SPECIFICS TO UI IMPLEMENTATION&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Lack of atomicity
&lt;/h3&gt;

&lt;p&gt;Another thing to look out for is chained tests that can not be run without each other. Having chained tests make the understanding and debugging of tests more complicated and also causes failure propagation. Failure of single test can lead to failure of all the subsequent tests also.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@FixMethodOrder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MethodSorters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;NAME_ASCENDING&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChainedTests&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// ... init ....&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;t1_canLoadPage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getAppUrl&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;until&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExpectedConditions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visibilityOfElementLocated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// DEPENDENT ON T1_canLoadPage&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;t2_canLogin&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"userid"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;sendKeys&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"login"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;until&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExpectedConditions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visibilityOfElementLocated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"order"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// DEPENDENT ON T1_canLoadPage and T2_canLogin&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;t3_canPlaceAnOrder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"order"&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;click&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;until&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExpectedConditions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;visibilityOfElementLocated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"confirmation"&lt;/span&gt;&lt;span class="o"&gt;)));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Unreliable selectors
&lt;/h3&gt;

&lt;p&gt;UI-based tests usually use some sort of selectors to identify the elements to interact with. Using unreliable and vague selectors can make your tests brittle and cause test failures even in case of minor UI changes around your test scope. For example, using absolute xpath or css locator can break when extra tag is added in the UI as parent or sibling of an particular element.&lt;/p&gt;

&lt;p&gt;Add unique locators in the product as needed to support testing. If this is not possible, identify stable ways to locate elements. Avoid using absolute css or xpath locators that are likely to break easily.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getDisclaimer&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ABSOLUTE XPATH LOCATOR THAT GETS EASILY BROKEN&lt;/span&gt;
        &lt;span class="nc"&gt;By&lt;/span&gt; &lt;span class="n"&gt;disclaimer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;By&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;xpath&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"html/body/div[1]/section/div[1]/div/div/div/div[1]/div/div/div/div/div[3]/div[1]/div/h4"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findElement&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;disclaimer&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getText&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Opportunity for learning
&lt;/h1&gt;

&lt;p&gt;Code reviews should not be seen only as a mean to identify problems in code. Reading others code and getting feedback for your own is a great way to improve your automation skills. There's always so much to learn from each others. &lt;/p&gt;

&lt;h1&gt;
  
  
  Means to an End
&lt;/h1&gt;

&lt;p&gt;The presented list aims to identify issues that can cause your test to be brittle, false, or make them hard to maintain. However, it doesn't aim to be ultimate truth about what is considered as bad practice. In some context using the presented approaches may be applicable or even only way to create workaround to get tests up and running. Sometimes it can be also reasoned for writing quick-n-dirty tests to verify something only once. Means to an end.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is a repost from an original article posted in &lt;a href="https://jperala.fi"&gt;jperala.fi&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>testautomation</category>
      <category>codereview</category>
    </item>
    <item>
      <title>10 Tips for Test Automation</title>
      <dc:creator>Juho Perälä</dc:creator>
      <pubDate>Fri, 18 Jan 2019 13:21:37 +0000</pubDate>
      <link>https://dev.to/juperala/10-tips-for-test-automation-2pc3</link>
      <guid>https://dev.to/juperala/10-tips-for-test-automation-2pc3</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Lost in test automation? Here is my selection of 10 tips for keeping your automation projects on the right track.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Getting started with test automation is easy. There are numerous automation tools and frameworks and plenty of material available on the internet to get started. With these even testers with no previous experience on test automation development can get their first tests up and running relatively quickly.&lt;/p&gt;

&lt;p&gt;However, what starts as a small and easy automation project tends to grow and become more complicated. As time goes by, new tests will be added, the need to support various product variants and versions becomes evident, test environments and tools change, people leave and join the project, and bunch of other unforeseen changes will happen. Without planning and clear focus automation projects can easily get bloated and side-tracked leading to exhaustive maintenance burden that will eventually reduce the benefits gained from the automation.&lt;/p&gt;

&lt;p&gt;This post will give ten pointers for getting started and keeping your automation projects on the right track. The list is not complete, but highlights common culprits and challenges observed in many automation projects.&lt;/p&gt;

&lt;h1&gt;
  
  
  Automation is a tool for testing, not a replacement
&lt;/h1&gt;

&lt;p&gt;The common misunderstanding across the IT industry is that all testing should be automated. In reality there is no 100% test automation – or at least it will not be cost-effective.&lt;/p&gt;

&lt;p&gt;Automated tests are merely checks that ensure software works as it was expected. As such, automation is an excellent tool for checking that nothing was broken when new product features were added and that new features work according to the specification. However, in practice it doesn’t make sense to check every imaginable detail of the product as it would eventually make your test suite unmaintainable. Automation also provides very limited or no support when it comes to identifying unknowns and unspecified product behaviour.&lt;/p&gt;

&lt;p&gt;Gaining understanding whether the developed features really fulfil your customer needs in given context and constraints still requires plenty of human thinking, communication, collaboration and exploration. Create automation that enables testers to focus on the essentials instead of doing repetitive tasks that are well suited for automation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Exploratory testing paired up with smart automation strategy is a killer combination for bug hunting. Empower testers to focus on critical thinking and brainwork by letting automation take care of the repetitive tasks. Focus on automation that will bring most value to your team.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Your tests are a product
&lt;/h1&gt;

&lt;p&gt;Many companies have well-defined processes and practices for developing quality software products, but may lack nearly all quality control when it comes down to developing and maintaining test assets. Test assets may be also developed and maintained by testers with limited software development and coding experience compared to full-time software developers.&lt;/p&gt;

&lt;p&gt;Although tests are not typically delivered to your customers with product releases, the lifecycle of your tests can be as long as the lifecycle of your products. Tests written today may be used for years after product delivery to ensure future maintenance updates and releases.&lt;/p&gt;

&lt;p&gt;To ensure your test assets are reliable, maintainable and easily extendable, good software development practices should be enforced. Also put focus on selecting right the automation tools and framework supporting your testing needs.&lt;/p&gt;

&lt;p&gt;A few things to think about in test asset development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Version control, branching, tagging, linking tests to product versions.&lt;/li&gt;
&lt;li&gt;Uniform and consistent coding convention.&lt;/li&gt;
&lt;li&gt;Self-describing test code naming (classes, methods, variables, commits).&lt;/li&gt;
&lt;li&gt;Configurability vs. hard-coded values and magic numbers.&lt;/li&gt;
&lt;li&gt;Quality practices &amp;amp; learning: Code reviews, pair- and mob programming.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Writing test automation is software development – treat it as such. Focus on having good quality test assets that are easily maintainable and follow good development practices. Value of test suite is on providing information about the product. Having unreliable and ambiguous test suite creating misinformation can be worse than not having tests at all.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  There is no “I” in automation
&lt;/h1&gt;

&lt;p&gt;The value of any testing is on providing information about the product to stakeholders. That in mind, automation should never be only your personal quest.&lt;/p&gt;

&lt;p&gt;Before starting out automation, get commitment from your team and organization. Define expected goals and scope for automation together, and include these in your team DoD (Definition of Done). Work together as a team, with support of both developers and testers, to achieve your goals.&lt;/p&gt;

&lt;p&gt;Make sure the results of automated tests are always up-to-date and available to your team and other stakeholders so they have the latest information to support development decisions. Automate only tests that provide meaningful information; there’s no point in automating things that nobody cares about.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Getting best value out of automation requires commitment from the whole team and organization. Work together. Create tests that bring value and meaningful information to your stakeholders.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Solid base
&lt;/h1&gt;

&lt;p&gt;Most testers starting to dabble with automation have their first experience usually with UI (GUI) automation tools. In web context, it’s commonly Selenium WebDriver or some test framework using Selenium under the hood. It makes perfect sense: as a tester you obviously want to test the whole application end-to-end, with all nuts and bolts installed. And Selenium is a great tool for that with plenty of resources and examples to get started.&lt;/p&gt;

&lt;p&gt;Alas, eventually you learn UI tests can be one of the most problematic tests to automate. First of all, they can be problematic regarding the project schedule. Testing the product via UI means you’ll need a working UI. However, that is often subject to continuous changes, fine-tuning and may be finalized in the very end of the project. Sometimes even the smallest UI changes can break your automation scripts, requiring excessive maintenance and refactoring work to keep up with the latest UI design. Secondly, implementation of UI based end-to-end tests with whole system in place have a tendency of being slower to execute and more brittle as there are more moving parts. Setting up test environment and test development is also usually more costly as there are more parts to configure and manage.&lt;/p&gt;

&lt;p&gt;Often teams put too much value on testing everything end-to-end in realistic environment with production UI. Aim to start automation as early as possible in the scope the functionality is implemented. Shift left. Have plenty of precise tests with detailed granularity, keep feedback loop fast from testing to development, and aim to develop tests that are robust to unrelated changes. Work your way up having relevant tests in each level, all the way from single units, to APIs, and finally to the UI layer. Usually this approach is described as a test pyramid, an idea initially coined by Mike Cohn and few others, where you should have solid base of unit and integration tests checking most of the things to be covered in testing.&lt;/p&gt;

&lt;p&gt;The test pyramid concept is also somewhat controversial and subject of numerous discussions in the community. My personal opinion is to use it as guideline, but not to take it too strictly as rule that can’t be broken. It’s not automatically wrong for example to have more end-to-end tests than integration tests automated. Also the cost and effort needed for solid unit test coverage can surprise in context where exhaustive use of mocking is required – test execution speed does not reflect the test implementation speed. Aim for shift left, don’t limit only to testing in one level, and adapt your way of working to find right balance of tests in your domain and context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Create solid base of unit and integration tests to catch most changes of the product, accompanied with smaller set of positive and negative end-to-end tests verifying overall functionality. Fill gaps with exploratory testing.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Don’t fall in love with your code
&lt;/h1&gt;

&lt;p&gt;It’s not uncommon to see test assets filled with obsolete information such unused classes and methods, commented-out code lines, outdated configuration files and obsolete test cases.&lt;/p&gt;

&lt;p&gt;Having obsolete code and test data makes the project hard to learn, follow and work with. Enforce good coding practices keeping the code base clean of obsolete and deprecated code that can become source for misinformation and technical debt. Create daily habit to cleanup obsolete test assets from repository.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Avoid technical debt and risk of misunderstanding. If test asset - whether it’s code, configuration, test, or anything else - becomes obsolete, thrash it. You have version control tools to keep track of the old versions in case you need to revert back to it.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  As weak as your test data
&lt;/h1&gt;

&lt;p&gt;To test deleting a bank account, you need to have a bank account created first. To test user login, you need a registered user information created. Practically all testing relies on the use of test data. How this data is created for testing purposes depends on the test scope and the context. In unit and integration tests, the test data may be generated using suitable mock interfaces and in-memory databases initialized at test setup, whereas a system-level test may rely on real database populated with SQL script, and so on.&lt;/p&gt;

&lt;p&gt;Especially for end-to-end testing of complex systems it may not be always trivial to automate the creation of realistic test data, and you may be tempted to use manually created test data in your automated tests. Although using manually created test data may be an applicable solution in some cases, it has in general many limitations that may bite you back later. Manually created data may expire unless maintained periodically, you may not be able to edit or delete it if other tests rely on it, and running multiple tests utilizing same data can cause flakiness and unexpected behaviour. The worst case would be using shared test data, such as data used both by automation and exploratory testing, that may change its state uncontrollably.&lt;/p&gt;

&lt;p&gt;Find ways to automate the creation of test data. Each test should rely on unique data that it may use, modify or delete on test execution. Ensure test data is always in a known state before test execution. Also remember to test the product with realistic data set sizes that are expected in production use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Success of automation depends on the quality of test data. Avoid use of manually configured, shared or uncontrollable test data. Find ways to mock, populate or virtualize data sources in your test environment to be suitable for your testing needs.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Works on my computer
&lt;/h1&gt;

&lt;p&gt;I bet everyone has heard someone retort “Works on my computer”? Too much time is wasted on investigation and fixing issues related to differences in various test environment configurations causing the software behave unexpectedly.&lt;/p&gt;

&lt;p&gt;Most often these problems are a consequence of manual setup and configuration of test environments leading to configuration nuances between different environments. Manual configuration is time consuming, prone to human errors, non-reproducible, and lacks rollback support to previous configurations. As a result, what works on your environment may not work on your colleagues’ - seemingly similar - environment and vice versa.&lt;/p&gt;

&lt;p&gt;Another challenge are unstable test environments that may fail randomly during test setup and execution. Unstable environments create misinformation in terms of false test results, eat up credibility of the testing, and analysing these errors take valuable time away from actual testing work. In worst case these environmental issues can kill the benefits otherwise gained from automation.&lt;/p&gt;

&lt;p&gt;Find ways to automate the setup and management of test environments. Use configuration management and virtualization tools (e.g. Docker, Puppet, etc.) to create infrastructure-as-code configuration that can be used throughout the development pipeline to setup reproducible development and testing environments for different phases and needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Focus on creating a pipeline from developer workstation to production where environments work in similar manner. Avoid manual configurations and create automated scripts for creation, configuration and deployment of test environments with suitable tools.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Timing is everything
&lt;/h1&gt;

&lt;p&gt;The world is asynchronous. Whether your tests are expecting response from native GUI, web application (browser), API or proprietary interface, the expected events will most likely be happening in an asynchronous manner. If your tests are not prepared for this, they may become flaky and fail unexpectedly due unknown response times of the application under test.&lt;/p&gt;

&lt;p&gt;Typical example of this is Selenium WebDriver based browser tests that can be extremely flaky unless appropriate waiting of correct web element state is used. In case the test does not wait an element to become present and visible before trying to interact with it, the test may fail unexpectedly. Too often these types of issues are resolved by adding fixed delay (sleep) before interaction. Although a common practise, it is a bad approach making the test slow to execute with no guarantee of stability unless excessively long delays are used. Preferred solution in this context would be to set up an explicit wait that waits until the element is ready for interaction.&lt;/p&gt;

&lt;p&gt;Regardless of used test tools and context, it is important to understand the implications that timing handling has to your tests, and how to mitigate them correctly to avoid test flakiness. Identify asynchronous events in test interactions and apply solutions to handle them without fixed delays.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;In your tests, know what is expected to happen and wait for it. Don’t rely on fixed delays that will slow down test execution with no guarantee for stability.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Simplify, isolate the unknown
&lt;/h1&gt;

&lt;p&gt;When developing automated tests, keep them as simple as possible. Keep tests short and avoid adding too much content in a single test (suite). Create test suites that focus on a specific feature of your product.&lt;/p&gt;

&lt;p&gt;Create tests that are atomic and well focused. Atomic tests are order independent and not dependent on the execution or results of other tests. Use suitable setup and teardown functions to keep the product in known state to achieve atomicity. Each test should have only one focus that it tests. Failure of test should explicitly identify the problematic part in the product without excessive result analysis.&lt;/p&gt;

&lt;p&gt;Tests should also be resilient to changes outside the test scope. Avoid using product features outside your defined test scope that may be subject to unexpected changes. As an example, if you are testing an embedded application that is part of a larger web portal, create tests that focus only on that specific app. When interacting with the application under test, create selectors that are resilient to changes that may happen in the portal page outside current test scope.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Keep your tests simple. Tests should tell directly what part of the product failed. Avoid vague shotgun tests without known scope. Create atomic tests that are resilient to changes happening outside the defined test scope to avoid test maintenance work and false negatives.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Don’t repeat yourself
&lt;/h1&gt;

&lt;p&gt;When working with multiple projects, or even single project with multiple test cases, avoid writing duplicate test code. If the same test step or functionality is used in multiple test suites and projects, modularize the functionality as its own test library that can be imported and reused in other projects.&lt;/p&gt;

&lt;p&gt;Creating reusable test modules and libraries brings multiple benefits. First, creating new projects will become easier as you will have a growing set of reusable functions available vs. always starting from the scratch. Second, it will ease the maintenance of the test assets when product functionality changes. When the functionality changes, the changes need to be done only in a single point in test code instead of refactoring all the related test projects and test cases.&lt;/p&gt;

&lt;p&gt;As you start creating reusable test libraries for your product, don’t forget to document and communicate availability of those libraries within your teams and organization. Otherwise there is a risk of individual teams creating duplicate test libraries causing risk of confusion and extra maintenance effort.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Reuse, reuse, reuse. Develop test modules and libraries to unify the way your tests behave. Avoid duplicate code and the need to fix same issue in multiple places.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Final thoughts
&lt;/h1&gt;

&lt;p&gt;Getting started with test automation can feel overwhelming. If you are a tester starting out automation without earlier programming experience, the learning curve can be especially steep while learning both coding and automation basics in parallel. But don’t stop. Keep going, learn and remember that no one is a master in the beginning.&lt;/p&gt;

&lt;p&gt;The great news is that there are great resources and communities to support your journey in automation. When stuck or unsure about the best way to continue, seek help. Check out available documentations, tutorials and resources on the Internet, read a book, or ask a question in testing communities such Ministry of Testing.&lt;/p&gt;

&lt;p&gt;Also check out available training and commercial offerings near you. There are many great services and companies with automation expertise to support, coach and ensure successful adoption of test automation in your organization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Start, keep going and get connected. There are great communities, events, trainings &amp;amp; partners to support your automation challenge.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is a repost from an original two-post article posted in &lt;a href="https://bitfactor.fi"&gt;Bitfactor Blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>testautomation</category>
      <category>softwaretesting</category>
    </item>
  </channel>
</rss>
