Automated Tester

.science

This content shows Simple View

C#

Use Selenium to Automate Windows with WinAppDriver

If you have ever found yourself in the position that you needed to automate a Windows application as part of your day to day automation testing you might well have come across AutoIt or gone down the CodedUI path. Now however, those good folk at Microsoft have made WinAppDriver which makes use of all the usual Selenium goodies… from the horses mouth:

Windows Application Driver is a service to support UI Test Automation of Windows Applications. The service design subscribes to the Mobile JSON Wire Protocol standard. If you’ve been looking for better support for using Appium to test Windows Applications then this service is for you!

The GitHub page has some good code samples to get you started (so I won’t bore you with any of mine), such as manipulating the Windows calculator. As you will see though the driver is still in beta but has come a long way recently and to help my foray into using it it now supports WCF applications.

Finding locators is pretty easy with the tool they suggest (Inspect) which is not too dissimilar to Spy++ if you have ever used that. Further to that I have found that the accessibility id locator works best for me (so far anyway!).

After installing the WinAppDriver executable, you can also run remotely which looks good but it does seem to only like being run on Windows 10 so you may need to take that into account if you don’t have the resources already in place.

If you decide to give it a whirl and encounter problems I would have a look at the issues page – chances are someone else has encountered it and a fix may already be underway.

Now obviously with WinAppDriver, this is only ever going to work with windows so I wouldn’t ever go recommending that this is used in the same project as your usual Selenium web based tests.

Until next time, have fun experimenting with WinAppDriver.



Testing Rest Endpoints with RestSharp and Specflow

In an earlier post I set how to use Specflow to test SOAP endpoints but what about REST API’s?

Given the nature of building URLs to interact with them it should be a cinch!… And it was. By leveraging use of the RestSharp library I was easily able to manipulate an example Rest interface over at http://www.thomas-bayer.com/sqlrest/.

So lets have a look at how:

Each method will be calling on the endpoint we initially set (the base URL), so lets wire in some tests with Gherkin and define some step definitions.

Scenario Outline: RestSharp Get Customer Record
Given I have an example endpoint http://www.thomas-bayer.com/sqlrest/
When I search for customer record 0
Then the result contains customer <ID>
Then the result contains customer <First Name>
Then the result contains customer <Last Name>
Then the result contains customer <Street>
Then the result contains customer <City>

Examples:
| ID | First Name | Last Name | Street | City |
| 0 | Laura | Steel | 429 Seventh Av. | Dallas |

Scenario: Post Product Price
Given I have an example endpoint http://www.thomas-bayer.com/sqlrest/
And I update the price of Product 1 to 10.00
When I search for Product 1
Then the price is 10.00
And I reset the price of product 1 to 24.8

We are passing the endpoint down to our helper here but I would normally put it in the App.config to keep things configurable.

Next up I created a Helper called RestHelper which will deal with all the setup, GET and POST requests etc. We need to define the endpoint and assign it to a commonly accessible place.

public class RestHelper
{
public RestClient endpoint = null;

public RestClient SetEndpoint(string endpointUrl)
{
endpoint = new RestClient(endpointUrl);
return endpoint;
}

Note: Your endpoints will most likely require some authentication of some kind which I am not covering. However I was easily able to add cookie authentication with a little tweaking.

Next lets create some other useful helper methods like GET and POST:

public string GetQuery(string query)
{
var request = new RestRequest(query, Method.GET);
IRestResponse response = endpoint.Execute(request);
var content = response.Content; // raw content as string
return content;
}

My POST method is simply to update the price of a product but you could rework to whatever you need:

public void UpdatePrice(string query, string price)
{
var request = new RestRequest(query, Method.POST) { RequestFormat = DataFormat.Xml };
var body = ("<resource><PRICE>" + price + "</PRICE></resource>");
request.AddParameter("text/xml", body, ParameterType.RequestBody);
endpoint.Execute(request);
}

In our Step definitions we just need to new up the Helper and pass in the right query, we are also assigning the Rest query result in a place that can be accessed by multiple step definitions:

private readonly RestHelper Rest = new RestHelper();

private string queryResult = null;

[Given(@"I have an example endpoint (.*)")]
public void GivenIHaveAnExampleEndpoint(string restEndpoint)
{
Rest.SetEndpoint(restEndpoint);
}

[When(@"I search for customer record (.*)")]
public void WhenISearchForCustomerRecord(string customerNo)
{
queryResult = Rest.GetQuery("CUSTOMER/" + customerNo + "/");
}

[Given(@"I update the price of Product (.*) to (.*)")]
[Then(@"I reset the price of product (.*) to (.*)")]
public void GivenIUpdateThePriceOfProductTo(int productNo, string newPrice)
{
Rest.UpdatePrice("PRODUCT/" + productNo +"/", newPrice);
}

And so on… If you want to have a play around with the code you can clone it from here and have fun testing REST APIs!



Setting up Marionette/ GeckoDriver

 

Firefox will crash if you are using the Webdriver implementation for FirefoxDriver with Firefox v47 and beyond. This needs to be replaced with Mozilla’s GeckoDriver/ Marionette. At the time of writing it is still in a pre-release stage; meaning you may get unpredictable results against the current stable version of Firefox. You may want to use it with Firefox Nightly or Firefox Developer.

Below are some steps to get you going with Marionette/ Geckodriver C# .Net:

  • Download the latest release here
  • Extract the *.exe middleware and rename it to ‘wires.exe’
  • Place ‘wires.exe’ in to the given source code location
  • Include ‘wires.exe’ into your Solution and set properties to ‘Copy if Newer’

To set the Driver up in code, I have found the following works well in C# .Net:

            FirefoxDriverService service = FirefoxDriverService.CreateDefaultService();
            service.FirefoxBinaryPath = @"C:\Path\to\your\FF\exe.exe";
            FirefoxOptions options = new FirefoxOptions();
            options.AddAdditionalCapability(CapabilityType.AcceptSslCertificates, true);
            TimeSpan t = TimeSpan.FromSeconds(10);

            Driver = new FirefoxDriver(service, options, t);

Note that you need to put in the path to your Firefox *.exe or add it to your system Path variable.

If you are experiencing issues I would recommend having a look at the project bug list or the project GitHub issues page before raising any issues. There is also much more information over at the Mozilla page for Marionette.



Specflow Reports with NUnit3

This post will look at setting up Specflow reports to work with NUnit3. When you install Specflow via NuGet, there is a tools folder which contains specflow.exe – if we run a batch process after the build on the CI server which points to the NUnit3 TestResult.xml, then we can generate a report and reference it as an artefact in TeamCity (and similar CI software).

But there is a catch, which isn’t (at the time of writing) explained in the Specflow reporting documentation. Currently Specflow (v 2.0.0) cannot interpret the NUnit3 TestResult output, so to counter this restriction we need to configure NUnit3 to output its TestResult.xml in the NUnit2 format. A full list of NUnit3 console options can be found here.

nunit3-console.exe –where cat==SmokeTests&&cat!=ExcludeFromCI
–out=TestResult.txt
–result=TestResult.xml;format=nunit2 C:\Path\To\Acceptance.Tests.dll

With this in place it’s now just a case of rigging up the Specflow command to point to the Test Result data and telling it to produce a report and specifying where to output the HTML report.

specflow.exe nunitexecutionreport Your.AcceptanceTest.csproj /testResult:TestResult.xml
 /out:MyResult.html

Once you have the TestResult.xml and the Result output generating where you want, it’s easy to wrap the command up into a batch file and call it from a build step after your tests have executed. Make this output an artefact and then you have metrics in place for your nightly and/ or other test builds.

Demo Specflow Report



Recording Videos of your Selenium Tests

It is good practice to take a screen grab of test failures and review them later, particularly if you have some bizarre wait or timeout error that can be difficult to pin down but sometimes even these can lead you down the wrong path or not give enough context to what went wrong. This led me to explore being able to capture videos of running tests that can be scrutinised at a later time, much like you get when you run tests in SauceLabs or BrowserStack.

I created a helper class called RecordVideo and pulled down a NuGet package called Microsoft Expression Encoder. You will also need to install Microsoft Expression Encoder 4.

Having set up a start (and stop) recording method we can easily capture tests in and write them out to file with the help of our set up or specflow hooks.

Here’s how:

using System;
using Microsoft.Expression.Encoder.ScreenCapture;

public class RecordVideo
{
private static readonly ScreenCaptureJob vidRec = new ScreenCaptureJob();

public static void StartRecordingVideo(string scenarioTitle)
{
string timestamp = DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss");
vidRec.OutputScreenCaptureFileName = @"C:\Test Videos" + scenarioTitle + " " + timestamp + ".wmv";
vidRec.Start();
}

public static void EndRecording()
{
vidRec.Stop();
vidRec.Dispose();
}
}

We can now call these in our setup/ teardown (in my case I’m using Scenario Hooks) and use the test case name for the file title along with a timestamp.

[BeforeScenario]
public void BeforeScenario()
{
RecordVideo.StartRecordingVideo(ScenarioContext.Current.ScenarioInfo.Title);
objectContainer.RegisterInstanceAs(new PageContext(TestRunContext.Driver));
}
[AfterScenario]
public void AfterScenario()
{
if (ScenarioContext.Current.TestError != null)
{
TakeScreenShot.SaveScreenShot(TestRunContext.Driver, TestFailurePath + ScenarioContext.Current.ScenarioInfo.Title + ".jpeg");
}

RecordVideo.EndRecording();
}

Be sure to put something in place to clear the directory out of videos on each run or you might find yourself running out of disk space quite quickly.




top