<?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: Matthias Barde</title>
    <description>The latest articles on DEV Community by Matthias Barde (@mbarde).</description>
    <link>https://dev.to/mbarde</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%2F58170%2F3043d2d6-47b8-48e0-b403-14b19736e66b.jpg</url>
      <title>DEV Community: Matthias Barde</title>
      <link>https://dev.to/mbarde</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mbarde"/>
    <language>en</language>
    <item>
      <title>Use Python to run parallel (and parametrized) Robot Framework tests</title>
      <dc:creator>Matthias Barde</dc:creator>
      <pubDate>Fri, 04 Oct 2019 09:32:06 +0000</pubDate>
      <link>https://dev.to/mbarde/use-python-to-run-parallel-and-parametrized-robot-framework-tests-1f7m</link>
      <guid>https://dev.to/mbarde/use-python-to-run-parallel-and-parametrized-robot-framework-tests-1f7m</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclaimer:&lt;/em&gt; I am neither an expert regarding the Robot Framework nor parallelization with Python. I simply found this possibility very use- (and learn-)ful and would like to share it whilst trying to explain how it works. &lt;br&gt;
If you are looking for more sophistiacted ways to execute concurrent Robot tests you should take a look at the &lt;a href="https://github.com/mkorpela/pabot"&gt;pabot library&lt;/a&gt; or &lt;a href="https://gettaurus.org/docs/Robot/"&gt;Taurus&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Requirements:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt; Knowledge of (and/or interest in) the Robot Framework&lt;/li&gt;
&lt;li&gt; Basic Python knowledge&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;... how to use concurrent subprocesses in Python&lt;/li&gt;
&lt;li&gt;... to run our Robot test multiple times in parallel&lt;/li&gt;
&lt;li&gt;... with different parameters without writing multiple tests (for example to allow testing with different test users)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;   👾 simple way performing stress tests against a system&lt;br&gt;
   🐢 speed up your testing&lt;br&gt;
   🐿️ fun&lt;/p&gt;
&lt;h3&gt;
  
  
  Excursion: Robot Framework
&lt;/h3&gt;

&lt;p&gt;From &lt;a href="https://robotframework.org"&gt;robotframework.org&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
Robot Framework is a generic open source automation framework for acceptance testing, acceptance test driven development (ATDD), and robotic process automation (RPA).
&lt;/blockquote&gt;

&lt;p&gt;Its Keyword based syntax is easy to learn and makes it possible to write human readable tests very fast.&lt;/p&gt;

&lt;p&gt;I like to use it together with the &lt;a href="http://robotframework.org/Selenium2Library/Selenium2Library.html"&gt;Selenium Library&lt;/a&gt; which provides a rich set of keywords for testing web pages and applications.&lt;br&gt;
In cases where those are not sufficient Robot Framework allows you to extend its functionality by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using additional &lt;a href="https://robotframework.org/#libraries"&gt;libraries&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Implementing your &lt;a href="http://robotframework.org/robotframework/3.0/RobotFrameworkUserGuide.html#creating-static-keywords"&gt;own keywords&lt;/a&gt; in Java or Python&lt;/li&gt;
&lt;li&gt;Executing Javascript via &lt;a href="http://robotframework.org/Selenium2Library/Selenium2Library.html#Execute%20Javascript"&gt;Selenium Keywords&lt;/a&gt; 🎉&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the &lt;a href="https://robotframework.org/#documentation"&gt;official documentation&lt;/a&gt; for more information and posibilites.&lt;/p&gt;
&lt;h1&gt;
  
  
  Let's start ⌨️
&lt;/h1&gt;
&lt;h3&gt;
  
  
  Parameterizing Robot tests
&lt;/h3&gt;

&lt;p&gt;We start with a single Robot test file called &lt;code&gt;suite.robot&lt;/code&gt; containing our test(s). This file contains a global variable for the login name of our test user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;${USER}           test-user
...

Login Test
    Go To    ${HOMEPAGE}
    Wait Until Element Is Visible    username
    Input Text    username    ${USER}
    Input Password    password    ${PASSWORD}
    ...

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Via &lt;a href="https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-command-line-options"&gt;command line options&lt;/a&gt; you are able to override the default value for this variable when running the test.&lt;/p&gt;

&lt;p&gt;For example&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;robot --variable USER:another-user suite.robot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;runs the test for the user &lt;code&gt;another-user&lt;/code&gt; (instead of &lt;code&gt;test-user&lt;/code&gt;).&lt;/p&gt;
&lt;h3&gt;
  
  
  Subprocesses with Python
&lt;/h3&gt;

&lt;p&gt;To make use of the above described options via Python we can use &lt;code&gt;subprocess.Popen&lt;/code&gt; (&lt;a href="https://docs.python.org/2.7/library/subprocess.html#subprocess.Popen"&gt;doc&lt;/a&gt;). Above example would be translated into:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;subprocess&lt;/span&gt;
&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'robot'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'--variable'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'USER:another@user.org'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'suite.robot'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;If you try this, you will see that the output of our Robot test gets logged to the console. This is not very helpful if you want to run multiple tests at the same time. &lt;br&gt;
We can disable this behavior by redirecting the output to &lt;code&gt;/dev/null&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="n"&gt;FNULL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;devnull&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'w'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FNULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Another argument for &lt;code&gt;Popen&lt;/code&gt; we will use is &lt;code&gt;cwd&lt;/code&gt;. It allows us to specify the working directory for the created process.&lt;br&gt;
This is useful since &lt;code&gt;robot&lt;/code&gt; will create the log files of our test in the current working directory. If we would run all our tests within the same directory those log files would collide. &lt;/p&gt;

&lt;p&gt;In our final script we make sure to create a separate folder per user, containing only the logs of the test for this user:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmdParts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;userPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FNULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Put it together
&lt;/h3&gt;

&lt;p&gt;Now we are able to put together a script expecting following files as input:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;suite.robot&lt;/code&gt; containing our Robot test(s)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user_list.txt&lt;/code&gt; containing list of usernames (one per line)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and doing the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a base folder containing our user folders&lt;/li&gt;
&lt;li&gt;Load &lt;code&gt;user_list.txt&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For each user:

&lt;ul&gt;
&lt;li&gt;a subfolder is created&lt;/li&gt;
&lt;li&gt;a subprocess is created running our test with the users parameter(s) within its subfolder&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Wait until all subprocesses finished&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Full script:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Possible improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make it more dynamic: Create input file containing arbitrary variable parameters per test (not only the username)&lt;/li&gt;
&lt;li&gt;Live view of each test in the console by redirecting &lt;code&gt;stdout&lt;/code&gt; more sophisticated&lt;/li&gt;
&lt;li&gt;Thread pool management (for example to restrict maximum number of concurrent subprocesses)&lt;/li&gt;
&lt;li&gt;Aggregated report&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thank you for reading :)&lt;/p&gt;

</description>
      <category>python</category>
      <category>testing</category>
      <category>concurrency</category>
      <category>robotframework</category>
    </item>
  </channel>
</rss>
