Selenium, NUnit, and Robot Framework Walkthrough
Let me start by saying, I'm not a frontend developer by no stretch of the imagination.
I don't do web pages, or UI's...
π
But...
As clearly stated in my profile (if it still there by the time you read this) I'm a development ecosystem enthusiast...
And I felt very enthusiastic about working with Selenium and Robot Framework.
The real story is, I was waiting for an opportunity to try out Selenium,
as a backend developer, these type of opportunities come few and far between.
That is until one day, I bumped into Robot Framework,
and I've noticed the framework has a SeleniumLibrary...
π π π That rang my two-for-the-price-of-one bell! π
So I decided to give it a whirl... And then I thought...
Well, lately I've been writing mostly Java,
maybe this is also an opportunity to brush up on my dotnet and C# skills.
π
So...
To make a long story short (if that's still possible),
Here's what I came up with, hope you'll enjoy it.
Walkthrough
This is an example C# WebApp tested using Selenium
browser automation with Nunit testing framework for unit tests
and Robot Framework automation framework for acceptance tests.
Base Requirements
-
.Net Core > 3 - written with
.Net Core 3.1.102
. -
Python > 3 - written with
Python 3.8.2
(used for the acceptance tests).
Before starting, please clone this repository and step into the solution folder.
It will be easier to follow this tutorial, as the next steps will assume you have done so:
git clone https://github.com/TomerFi/selenium-nunit-robotframework-tutorial.git
cd selenium-nunit-robotframework-tutorial
Web Application
In src/DemoWebApp
, you'll find a simple C# WebApp
created from the basic template provided with dotnet
.
On top of the base application I've added:
- a
button
tag with the id clickmeButton. - a
h2
tag with the id displayHeader and the initial content text of Not clicked. - a
script function
called clickButton invoked by a click event from the clickmeButton and changes the displayHeader's content text to Button clicked.
I've added these elements in src/DemoWebApp/Pages/Index.cshtml
.
Other than that I've changed nothing from the basic template:
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
<button id="clickmeButton" type="button" onclick="clickButton()">Click Me!</button>
<h2 id="displayHeader">Not clicked</h2>
</div>
<script>
function clickButton() {
document.getElementById("displayHeader").textContent = "Button clicked";
}
</script>
To run the project and serve the app at http://localhost:5000
:
dotnet run -p src/DemoWebApp
Unit Testing
In tests/DemoWebApp.Tests
, you'll find the test project for performing unit tests, I've used:
- Nunit as the testing framework for the project.
- Selenium as the toolset providing browser capabilities and automation.
tests/DemoWebApp.Tests/DemoWebAppTest.cs
is test class, Nunit
will pick it up based on its name:
I've used the OneTimeSetup
attribute to spin-up the server before executing the test cases:
[OneTimeSetUp]
public void SetUpWebApp()
{
app = DemoWebApp.Program.CreateHostBuilder(new string[] { }).Build();
app.RunAsync();
}
And the OneTimeTearDown
attribute to shutdown the server afterward.
[OneTimeTearDown]
public void TearDownWebApp()
{
app.StopAsync();
app.WaitForShutdown();
}
The test itself is pretty straightforward:
- It first navigates to the server at
http://localhost:5000
. - It will then find the
button
element by its id and click it. - Finally, it will make sure the
h2
element's content text isButton clicked
.
The assert statement evaluates the clicked
boolean value,
which will be false if expected test conditions are not met within 10 seconds.
public void TestButtonClick(Type drvType)
{
bool clicked;
using (var driver = (IWebDriver)Activator.CreateInstance(drvType))
{
var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
driver.Navigate().GoToUrl("http://localhost:5000");
driver.FindElement(By.Id("clickmeButton")).Click();
clicked = wait.Until(ExpectedConditions.TextToBePresentInElement(
driver.FindElement(By.Id("displayHeader")), "Button clicked"));
}
Assert.True(clicked, "button not clicked.");
}
The test-cases will invoke the TestButtonClick
test 3 times, one for each TestCase
.
The result will be 3 tests performed, one with the chrome
driver, one with the firefox
driver, and one with the ie
driver.
[TestCase(typeof(ChromeDriver))]
[TestCase(typeof(FirefoxDriver))]
[TestCase(typeof(InternetExplorerDriver))]
public void TestButtonClick(Type drvType)
{
...
}
To check it out, just:
dotnet test
Acceptance Testing
For acceptance tests I've used:
- Robot Framework as the automation framework for executing the tests.
- SeleniumLibrary as the library providing browser capabilities and automation.
For the next steps, step into the acceptance
folder.
The acceptance tests don't have, nor should it have, any direct
connection to the solution's base code.
Prepare Environment
Robot Framework
is a python tool, it requires a python binary and some requirements.
Assuming you have Python installed, and you're in the acceptance
folder,
Just do:
pip install --upgrade -r requirements.txt
As this is the acceptance tests part, the tests need a web server serving the web app.
You can follow the Web Application section to run the web app locally, or run it as you see fit.
just don't forget to set the URL
variable in acceptance/resources.robot
to the correct address:
${URL} http://localhost:5000
Please note, markdown doesn't support robotframework syntax highlighting natively.
There's another version of this tutorial in restructuredText which supports robotframework syntax highlighting
here.
Drivers
You can download the drivers stored in acceptance/drivers
with the following links.
Just mind the versions and make sure they're in conjunction with the versions used in
tests/DemoWebApp.Tests/DemoWebApp.Tests.csproj
:
<ItemGroup>
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="83.0.4103.3900" />
<PackageReference Include="Selenium.WebDriver.IEDriver" Version="3.150.1" />
<PackageReference Include="Selenium.Firefox.WebDriver" Version="0.26.0" />
</ItemGroup>
To save you the troubles, here are the links for the drivers download:
Tests
acceptance/webapp_tests.robot
is the test suite
.
It declares 3 Test Cases
, one for each driver.
Each test-case uses Test Template
with its own Browser
and Executable
arguments.
Make sure the driver executables are in the correct path.
*** Settings ***
...
Test Template Press Button
*** Test Cases *** Browser Executable
Test With Chrome chrome drivers/chromedriver
Test With Internet Explorer ie drivers/iedriver
Test With Firefox firefox drivers/geckodriver
The Test Template
invokes the keyword named Press Button
,
For each execution, what Press Button
does is pretty self-explanatory by its BDD
nature:
*** Keywords ***
Press Button
[Arguments] ${browser} ${executable}
Open Browser With Url ${browser} ${executable}
Click Test Button
Validate New Text
[Teardown] Close Browser
The result of running this test suite will be 3 tests, one for each driver, each pressing the button and validating the side effects.
The Press Button
uses 4 other keywords to perform its action.
As you can see in the Settings
section, I've declared acceptance/resources.robot
as a resource.
It provides us with the following custom keywords:
Open Browser With Url
Click Test Button
Validate New Text
The 4th keyword, Close Browser
, is not a custom one, it comes from SeleniumLibrary, imported within acceptance/resources.robot
:
*** Settings ***
...
Library SeleniumLibrary
The same library is also used in by the custom keywords in acceptance/resources.robot
.
To execute the acceptance tests, simply run:
robot -d rfoutput webapp_tests.robot
This will run the tests and save a pretty and useful HTML report summary and xml logs in a folder called rfoutput
(gitignored).
You can see an example of the summary report here.
Links
- GitHub repository
- Nunit3 home
- Nunit3 docs
- Selenium home
- Selenium docs
- Robot Framework home
- Robot Framework docs
- SeleniumLibrary home
- SeleniumLibrary docs
π See you in the next tutorial π
Discussion (0)