Automation of testing Windows-applications using Winium
What to eat with
With Winium, we can automate regular Windows applications. As a rule, Winium can work with those elements that can be found in windows using standard Windows tools (as a rule, these elements have a tab order). These tools are supplied in standard kits (for example, you can download them here , after installation, look for them, for example, here: C: \ Program Files (x86) \ Windows Kits \ 8.1 \ bin \ x64). I consider inspect and uiverify the most convenient for myself , but the taste and color, as some of my comrades say, all the markers are different.
However, in order to automate self-written applications, it would be nice for fellow developers to ensure that the elements have adequate ClassName, Name, and AutomationId. Of course, in certain situations, we can be saved by transmitting keystrokes of certain keys and clicking on the coordinates, but this is not a panacea. It is better to always have a set of pre-prepared “levers” in the form of object descriptions than to rely on the fact that the GUI will always be unchanged and will behave well in various situations.
With Winium in normal mode, you can communicate using Selenium using Python and Java; one way or another, but the stars stood so that the choice fell on Java.
Installation
First, we need the Winium Desktop Driver. You can download it, for example, here . We will be required to unzip this case and run it during tests. Through it, the Selenium server will communicate with Windows applications.
Secondly, in fact, the Java-IDE (used by IntelliJ IDEA Community, for which a special thank you to them) and the JDK. Do not forget to check / register the JAVA_HOME environment variable with the value of the path to the JDK (in my case, C: \ Program Files \ Java \ jdk1.8.0_131).
Thirdly, we need a Selenium server too - go here , download the Selenium Standalone Server (JAR file).
Next, on setting up the project - create a new Java project and add it to External libraries (click on the Project Structure button (or Ctrl + Alt + Shift + S), there inProject Settings , select Libraries and click the plus sign ) our seleniumny JAR-file. That's all, you can write.
Using
In order for everything to work, you need to run Winium.Desktop.Driver with admin rights while using the tests. But, since the driver can freeze from time to time for one reason or another, it is convenient to run it before each test and kill it at the end. For example, you can use ProcessBuilder for this purpose:
ProcessBuilder pro = new ProcessBuilder(windriverPath + windriverName, windriverParam);
shell = pro.start();
//<наш код>
shell.destroy();
where, for ease of deployment, you can specify windriverPath , windriverName - the path to the driver and the name of the executable file; windriverParam - additional launch options, if required.
At the beginning, in the code, you need to attach the driver variable to the actual Winium driver:
DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability("app",""); //если хотим сразу запускать какую-либо программу
cap.setCapability("launchDelay","5"); //задержка после запуска программы
WebDriver driver = new RemoteWebDriver(new URL("http://localhost:9999"),cap); //на этом порту по умолчанию висит Winium драйвер
If we do not want to run some application, but simply attach to any already running, then lines 2 and 3 can be safely omitted.
In order for us to work with any element, we first need to attach to it. Three attachment mechanisms are known - By.name - by the Name field, By.className - by the ClassName and By.xpath fields for more sophisticated search conditions. Also, if we need the first / only element, we can use the findElement method , and if we want to get a list of all such elements, then we need to use the findElements method . In the second case, the elements will be added in the order of the tab order. Examples of using:
WebElement wrk = driver.findElement(By.name("Значение поля Name")); //один элемент, поиск по полю Name
List wrkL = driver.findElements(By.className("Значение поля ClassName")); //список элементов с заданным полем ClassName
We can also attach to elements of another element:
WebElement wrk1 = wrk.findElement(By.name("Значение поля Name"));
If the first two attachment mechanisms are highly specialized, i.e. work strictly in a hierarchical structure and strictly with the Name and ClassName fields, then to work with other cases we need a third mechanism, namely By.xpath .
In this mechanism, everything is strictly according to the canons of using xpath (in any case, everything worked as it should from the cases used). Using xpath, you can get and process the fields IsOffscreen, AutomationId, HasKeyboardFocus:
WebElement field = wrk.findElement(By.xpath("*[@HasKeyboardFocus='True']")); //найдёт элемент у wrk, на котором стоит фокус
When using xpath, especially if we are working in more complex conditions, it is convenient to track the entire string passed to xpath to track probable errors:
String xpathStr = "*[(@AutomationId='" + autId + "') and (@IsOffscreen='False')]"; //будем искать элемент у текущего окна с каким-то заданным AutomationId = autId и у которого свойство IsOffscreen = False
log("Performing xpath search: " + xpathStr);
WebElement tWrk = wrk1.findElement(By.xpath(xpathStr));
Of course, we can search with xpath for elements not only of the current window, but such a search can last quite a long time.
There are other search methods, but one way or another, it all comes down to the ones described above. For example, such .
We may also need to simulate keyboard input from a keyboard. In the usual manner, this is done using the sendKeys method ("Sequence of characters")at the item. However, it should be remembered that some characters are used as service characters and they must be escaped (for example, “+” is Shift, and in order to enter “+”, you need to pass the sequence “+ =”). For the convenience of using the code, you can write a wrapper that would automatically replace all "+" with "+ =", but here it’s more convenient for anyone. You can familiarize yourself with the transmission standards for keyboard shortcuts, for example, here . Nevertheless, there were problems with the correct transfer of keystrokes on the keyboard, so unfortunately, with the current version of the driver, you will have to look for workarounds.
One of these workarounds is clicking on the coordinates with respect to a given element. This is not the most trivial task, but here you can use Actions:
Actions builder = new Actions(driver);
Action enter = builder
.moveToElement(wrk)
.moveByOffset(x,y)
.click()
.build();
enter.perform();
where wrk is the name of the WebElement, from the center of which we will move the mouse; x , y - the distance we will move (a positive value of x moves the cursor to the right, a positive y - down).
Just a little bit about the overall structure of the project
As was already noted slightly above, the main element of interaction with the outside world is “leverage”. They can be conveniently described by a class with the fields name , className and automationId and stored in separate classes in blocks.
Since automatic tests often repeat any steps of each other, these procedures are also conveniently formatted as separate static methods and also stored in separate classes in blocks.
Everything else can be safely done as usual - classes with tests, a class for running tests, and more.
Conclusion
In general, immersion in the Winium world is quite interesting and not very difficult. Thanks to all the readers who read this post to the end. I really hope that this post will help someone in the development of Winium. Special thanks to my partner Eugenia, with whom we plunged into his wilds. Good to all!