📜 ⬆️ ⬇️

From bike to ...

Hello!

This small essay is addressed to QA - specialists and more developers who are involved in automating web and mobile application testing. Those who are simply interested in open source 'ohm are welcome too.

Here I want to develop the thoughts expressed a year ago in the article "About Selenium and one" bicycle " . "
')
Plan:
1. Basic features (overview)
2. How to develop (lyrical digression)
3. Conclusion.

You can immediately familiarize yourself with the solution . But if it is interesting to first read the article -
go!



1. Basic features (overview)




As you already understood, the solution is written in Java 8. The main components are Selenium (to provide interaction with desktop browsers), Appium ( java-client , to ensure interaction with mobile browsers and applications).

If we talk about the principle and method of working with Selenium Webdriver, then it is somewhat similar to what offers such solutions as Html elements from Yandex and Thucydides . But all this is somewhat revised.

What turned out, I am associated with some arthropod creature. Considering that Selenium and Appium find their application in test automation + we all know the translation of the word bug, we got such a name for the solution - Arachnidium (lat. "Arachnid").

So.

Cross-browser compatibility


I think this point is taken for granted. But it is necessary to mention.

Supported:
- Firefox;
- Chrome;
- Internet Explorer;
- Safari;
- PhantomJS.
- Remote launch of the browsers listed above.
HtmlUnitDriver and OperaDriver had to be abandoned. The first is not the successor of RemoteWebDriver and its support is fraught with crutches, the second is outdated (for example, it does not launch Opera on Windows 8 / 8.1). But there is a current replacement:
- Chrome for Android. A little later I want to add support for the native browser Android and Chromium
- Mobile Safari for iOS

Support for automating interaction with native and hybrid mobile apps UI.



This is possible due to the intensive use of the capabilities of Appium.

But even this is not, in my opinion, the most interesting.

The ability to simulate the user interface of the application in parts and as a whole.


I described these principles in detail here , here and here (in English). But in order not to distract readers, I will probably quote something, something more effective.

For my tests on Android, I use the BBC News app. Its UI is very similar to the site's UI in terms of the visual composition of the elements. Suppose you need to test both the site and the Android application. Then you can describe the user interface as follows.

List and view news:

Code under the cut
/** * Imagine that we have to check browser and Android versions * How?! See below. */ @IfBrowserURL(regExp = "http://www.bbc.com/news/") @IfMobileContext(regExp = "NATIVE_APP") @IfMobileAndroidActivity(regExp = "HomeWwActivity") public class BBCMain extends FunctionalPart<Handle>{ @FindBy(className = "someClass1") @AndroidFindBy(id = "bbc.mobile.news.ww:id/articleWrapper") private List<RemoteWebElement> articles; @FindBy(className = "someClass2") @AndroidFindBy(id = "bbc.mobile.news.ww:id/articleWebView") private RemoteWebElement currentArticle; @FindBy(className = "someClass3") @AndroidFindBy(id = "bbc.mobile.news.ww:id/optMenuShareAction") private RemoteWebElement share; @FindBy(className = "someClass4") @AndroidFindBy(id = "bbc.mobile.news.ww:id/optMenuWatchListenAction") private RemoteWebElement play; @FindBy(className = "someClass5") @AndroidFindBy(id = "bbc.mobile.news.ww:id/optMenuEditAction") private RemoteWebElement edit; @FindBy(className = "someClass6") @AndroidFindBy(uiAutomator = "new UiSelector().resourceId" + "(\"bbc.mobile.news.ww:id/optMenuRefreshAction\")") private RemoteWebElement refresh; protected BBCMain(Handle context) { super(context); load(); } @InteractiveMethod public int getArticleCount(){ return articles.size(); } //some more staff //... } 



Form selection of news by categories:

Code under the cut
 /** * Imagine that we have to check browser and Android versions * How?! See below. */ @IfBrowserURL(regExp = "http://www.bbc.com/news/") @IfMobileContext(regExp = "NATIVE_APP") @IfMobileAndroidActivity(regExp = "PersonalisationActivity") public class TopicList extends FunctionalPart<Handle> { @CacheLookup @FindBys({@FindBy(linkText = "someLink"), @FindBy(linkText = "someLink2"), @FindBy(linkText = "someLink2")}) @AndroidFindBys({@AndroidFindBy(id = "bbc.mobile.news.ww:id/personalisationListView"), @AndroidFindBy(className = "android.widget.LinearLayout"), @AndroidFindBy(uiAutomator = "new UiSelector()"+ ".resourceId(\"bbc.mobile.news.ww:id/feedTitle\")")}) private List<WebElement> titles; @CacheLookup @FindBys({@FindBy(linkText = "someLink3"), @FindBy(linkText = "someLink4"), @FindBy(linkText = "someLink5")}) @AndroidFindBys({@AndroidFindBy(id = "bbc.mobile.news.ww:id/personalisationListView"), @AndroidFindBy(className = "android.widget.LinearLayout"), @AndroidFindBy(uiAutomator = "new UiSelector()."+ "className(\"android.widget.CheckBox\")")}) private List<WebElement> checkBoxes; @AndroidFindBy(id = "bbc.mobile.news.ww:id/personlisationOkButton") private WebElement okButton; protected TopicList(Handle context) { super(context); load(); } //some more staff //... } 



Test (the most simplified view):

Android

Code under the cut
  @Test public void androidNativeAppTest() { Configuration config = Configuration .get("android_bbc.json"); Application<?,?> bbc = MobileFactory.getApplication( Application.class, config); try { BBCMain bbcMain = bbc.getPart(BBCMain.class); Assert.assertNotSame(0, bbcMain.getArticleCount()); bbcMain.selectArticle(1); Assert.assertEquals(true, bbcMain.isArticleHere()); bbcMain.edit(); TopicList<?> topicList = bbcMain.getPart(TopicList.class); topicList.setTopicChecked("LATIN AMERICA", true); topicList.setTopicChecked("UK", true); topicList.ok(); bbcMain.edit(); topicList.setTopicChecked("LATIN AMERICA", false); topicList.setTopicChecked("UK", false); topicList.ok(); } finally { bbc.quit(); } } 



Browser (desktop / mobile)

Code under the cut
 @Test public void webTest() { Configuration config = Configuration .get("android_some_browser.json"); Application<?,?> bbc = WebFactory.getApplication( Application.class, config, urlToBBCNews); //does the same 



About some things I will talk about later.

I tried to implement a universal (rather, conditionally universal) model so that the developer of the framework for autotests (and I see myself in this role, for myself I don’t do well :)) did not multiply the code but could make it independent of the environment (I mean by the way the test is performed is in the browser or is it the native content / html content of the hybrid application).

Used design - Page Object pattern. My version assumes that pages / screenshots can be described both in whole and in parts, if there are duplicate widgets or sets of elements. You can even make the whole application behave like a Page Object!

Another feature is that many technical nuances associated with the need to manage an instance of WebDriver in situations where several browser windows are present at the same time (or contexts if the mobile application) and some of the content is placed in ifram are automated. So you can fully focus on the description of the business logic!

Architecture.



In modern conditions, my IMHO, decides not a monolithic architecture, but a modular or "transparent". I tried to implement everything in such a way that it was possible to use both standard solutions of Selenium and Appium (this method of decorating elements in my solution is used by default), for which I tried to provide convenient ways of working, and, theoretically, third-party solutions.

Here are examples:

- joint work with HtmlElements from Yandex. Link
- collaboration with Selenide from Codeborne. Link
- use of Thucydides. Link Who is interested in - a report for the web (GoogleDrive) and a report for Android (BBC News, a Genymotion virtual machine that emulates an Android tablet). Happy viewing and do not forget to unpack. I want to do a similar sample for Allure later.

Setup Method

In this case, I mean the transfer and storage of parameters for launching browsers and mobile applications (as was intended from the very beginning). Described in detail here . But how to be. I will give an example.

Let there is a general setting stored in the settings.json file attached to the project.

JSON with default parameters
 { "settingA": { "aValue":{ "type":"STRING", "value":"AAA" } }, "settingB": { "bValue":{ "type":"STRING", "value":"bbb" } }, "settingC": { "cValue":{ "type":"STRING", "value":"C" } }, "settingD": { "dValue":{ "type":"STRING", "value":"D..." } } } 



And there is a file, named differently, containing such data that, as it were, overlaps the data from the example above.

JSON with custom parameters
 { "settingB": { "bValue":{ "type":"INT", "value":"1" } }, "settingC": { "cValue":{ "type":"BOOL", "value":"true" } } } 



Code below

code
 import com.github.arachnidium.util.configuration.Configuration; import org.junit.Before; import org.junit.Test; public class DemoTest { Configuration testConfig; private String aGroup = "settingA"; private String bGroup = "settingB"; private String cGroup = "settingC"; private String dGroup = "settingD"; private String aValue = "aValue"; private String bValue = "bValue"; private String cValue = "cValue"; private String dValue = "dValue"; @Before public void setUp() throws Exception { testConfig = Configuration.get("src/test/resources/test.json"); } @Test public void test() { Object a = Configuration.byDefault.getSettingValue(aGroup, aValue); Object b = Configuration.byDefault.getSettingValue(bGroup, bValue); Object c = Configuration.byDefault.getSettingValue(cGroup, cValue); Object d = Configuration.byDefault.getSettingValue(dGroup, dValue); System.out.println(a); System.out.println(a.getClass()); System.out.println(b); System.out.println(b.getClass()); System.out.println(c); System.out.println(c.getClass()); System.out.println(d); System.out.println(d.getClass()); System.out.println(); System.out.println(); System.out.println("Showtime! Customized setting see below."); System.out.println(); System.out.println(); a = testConfig.getSettingValue(aGroup, aValue); b = testConfig.getSettingValue(bGroup, bValue); c = testConfig.getSettingValue(cGroup, cValue); d = testConfig.getSettingValue(dGroup, dValue); System.out.println(a); System.out.println(a.getClass()); System.out.println(b); System.out.println(b.getClass()); System.out.println(c); System.out.println(c.getClass()); System.out.println(d); System.out.println(d.getClass()); } } 



gives this output to the console

what console output
 AAA class java.lang.String bbb class java.lang.String C class java.lang.String D... class java.lang.String Showtime! Customized setting see below. AAA class java.lang.String 1 class java.lang.Integer true class java.lang.Boolean D... class java.lang.String 



Thus, it is assumed that there is a general setting in which the default data is indicated, and a set of such configurations that partially overlap or refine this data. Moreover, if the data is not specified in such a custom - general information will be used.

I intend to use such a mechanism to start browsers and mobile applications. But, in principle, it can find wider application due to its flexibility and extensibility.

At this point I finish my review. There are other interesting things here. Maybe I will talk about them in another article or in comments to this.

2. How to develop (lyrical digression).




For most of my professional biography, I was involved in automating the testing of desktop software, mainly using Test Complete . There was a lot of interesting and non-trivial. But I'm tired. Drawn on some creativity.

Later I found out about Selenium Webdriver (and who doesn't know now?). At first there were just experiments. Then ideas began to appear. Although ... I took them from the accumulated practice. For example, such a concept as Page Object and examples of implementation did not cause my Wow effect. Something similar had to be done for desktop applications.

The experiment described in the chapter above was discontinued and resumed several months later.

Next, I learned about Appium. I even happened to participate in this project! Participation began spontaneously - with reporting bugs and what seemed to me problematic. Later a client library for java: java-client appeared . Here the contribution is more serious. I managed to implement features for working with PageFactory and help with library redesign, as a result of which AndroidDriver and IOSDriver appeared and flexibility appeared, if you need to add support for Firefox OS and Windows Mobile. Hope this helped many other people around the world.

3. Conclusion.


I would be glad to communicate in the comments.

I brought this experiment to such a state that it is not a shame to say that builds are available in the maven central . For now, I would suggest playing with them or trying to automate some simple test case.

If someone finds a bug, it's awesome! Please describe it here . And in the comments it would be great to read criticism, ideas, if someone praises - that’s good too.

On the described do not want to stop. There is an idea to continue the banquet - to implement plug-ins for JUnit, TestNG and Jbehave. You can make a plugin, for example, for the Eclipse IDE, but I can hardly imagine its functions for now. In addition - there is still an empty C # project. But! All this makes sense if basic functionality is needed. Always happy pull requests!

See you!

Source: https://habr.com/ru/post/241798/


All Articles