📜 ⬆️ ⬇️

SWD.Starter: Quick Start Automation Testing UI on C # + Selenium WebDriver + PageObjects

WTF Logo
The article will cover how to set up a C # automated user interface testing framework, along with Selenium WebDriver and the PageObjects pattern.

The open source starter kit - SWD.Starter - will help you write and run your first test in 10 minutes. In addition, offering a framework architecture based on good testing automation practices.
All SWD.Starter code can be completely customized for your needs.


What is SWD.Starter?


SWD.Starter is a starter kit for your test automation framework. All source code is available on GitHub: dzhariy / SWD.Starter , and the license of the project (unlicense) allows you to use the source code as you like, even to sell.
')
SWD.Starter is an already configured project that contains all the necessary infrastructure code to start creating and running user interface tests through Selenium WebDriver.

SWD.Starter strongly recommends the use of the PageObjects pattern. And in the case of using this pattern, you will be able to write a new code for auto tests really quickly, while maintaining the beautiful architecture and readability of the code.

What you need to start


To run the project, you will need the following software:

  1. Visual Studio Express 2013 Desktop Edition (also, in theory, supported by VS2010 and VS2012)
  2. Git to download a project from Github
  3. Additional drivers for Selenium WebDriver browsers that can be downloaded from the official project page

For quick and easy software installation, I recommend using Chocolatey's Windows package manager.
According to the instructions on the main page, open cmd.exe, and in the console window, simply execute the following code:

@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin 

And further, in the same console window, execute the following commands:

Now, in the console window (for example, in cmd.exe or Far Manager), select the folder where you want to clone SWD.Starter - and run the command:
 git clone https://github.com/dzhariy/SWD.Starter.git 


This is a required step, otherwise the project will not compile:
Copy chromedriver.exe and IEDriverServer.exe to the SWD.Starter \ webdrivers folder

But the full installation video on a clean virtual machine (which I downloaded from modern.ie )
Follow the pink pokemon, Neo!

Just in case, I note that the video shows that Windows on the virtual machine requires activation.
According to the license terms of modern.ie, I have the right to use such images legally for testing purposes. The user agreement states that I should not activate Windows in this case.


What is PageObjects and why is it so important?


Simply put, the approach to automated testing using PageObjects is that you simply take out all the low-level page work code (for example, typing and clicking on elements) into separate classes.

Now your tests do not work with the page directly, calling the low-level WebDriver methods, and use higher-level operations specific to each page.

This reduces the number of lines of code in the tests, thereby making the code more readable, understandable and reliable.
The PageObjects approach is an alternative to the bot style - calling the WebDriver methods from tests directly.
At the very beginning, the bot style seems simpler and clearer than using PageObjects. But, this is a huge misconception that your automation project may crash.

Over time, when the number of tests will grow, if you use a bot-style, you will spend more and more time supporting them. As a result, support for the automation framework will not be economically viable and the project management will decide to return to manual testing. And already written code will only be thrown away, due to the fact that it no longer corresponds to the actual application under test.

Bot-style tests are like a huge, un-sorted pile of books. When your “heap” consists of only 10 books, you can understand it without any particular difficulties.
But what awaits you when the number of books increases to 100? Believe me, I do not envy you. Just because he has already been through it.
Heap of books

On the other hand, when using PageObjects, you can decompose all the books on the shelves. In bookstores and warehouses, contains a huge number of books. However, sellers can quickly find what you need.
PageObject-class is a bookshelf that allows you to conveniently organize the code to work with a web page. And popular programming languages ​​and IDE provide much more opportunities when using object-oriented programming.

Book shelf

Bot-style tests


The main advantage of bot-style tests is that you can “write them without even knowing the programming language” using tools such as Selenium IDE and Selenium Builder.

As a result, something can turn out:
Very long type code sheet: driver.FindElement (By.Id (ConfirmPassword)). SendKeys (pass);
 class BrittleTest { [Test] public void Can_buy_an_Album_when_registered() { var driver = Host.Instance.Application.Browser; driver.Navigate().GoToUrl(driver.Url); driver.FindElement(By.LinkText("Admin")).Click(); driver.FindElement(By.LinkText("Register")).Click(); driver.FindElement(By.Id("UserName")).Clear(); driver.FindElement(By.Id("UserName")).SendKeys("HJSimpson"); driver.FindElement(By.Id("Password")).Clear(); driver.FindElement(By.Id("Password")).SendKeys("!2345Qwert"); driver.FindElement(By.Id("ConfirmPassword")).Clear(); driver.FindElement(By.Id("ConfirmPassword")).SendKeys("!2345Qwert"); driver.FindElement(By.CssSelector("input[type=\"submit\"]")).Click(); driver.FindElement(By.LinkText("Disco")).Click(); driver.FindElement(By.CssSelector("img[alt=\"Le Freak\"]")).Click(); driver.FindElement(By.LinkText("Add to cart")).Click(); driver.FindElement(By.LinkText("Checkout >>")).Click(); driver.FindElement(By.Id("FirstName")).Clear(); driver.FindElement(By.Id("FirstName")).SendKeys("Homer"); driver.FindElement(By.Id("LastName")).Clear(); driver.FindElement(By.Id("LastName")).SendKeys("Simpson"); driver.FindElement(By.Id("Address")).Clear(); driver.FindElement(By.Id("Address")).SendKeys("742 Evergreen Terrace"); driver.FindElement(By.Id("City")).Clear(); driver.FindElement(By.Id("City")).SendKeys("Springfield"); driver.FindElement(By.Id("State")).Clear(); driver.FindElement(By.Id("State")).SendKeys("Kentucky"); driver.FindElement(By.Id("PostalCode")).Clear(); driver.FindElement(By.Id("PostalCode")).SendKeys("123456"); driver.FindElement(By.Id("Country")).Clear(); driver.FindElement(By.Id("Country")).SendKeys("United States"); driver.FindElement(By.Id("Phone")).Clear(); driver.FindElement(By.Id("Phone")).SendKeys("2341231241"); driver.FindElement(By.Id("Email")).Clear(); driver.FindElement(By.Id("Email")).SendKeys("chunkylover53@aol.com<script type="text/javascript"> /* <![CDATA[ */ (function(){try{var s,a,i,j,r,c,l,b=document.getElementsByTagName("script");l=b[b.length-1].previousSibling;a=l.getAttribute('data-cfemail');if(a){s='';r=parseInt(a.substr(0,2),16);for(j=2;a.length-j;j+=2){c=parseInt(a.substr(j,2),16)^r;s+=String.fromCharCode(c);}s=document.createTextNode(s);l.parentNode.replaceChild(s,l);}}catch(e){}})(); /* ]]> */ </script>"); driver.FindElement(By.Id("PromoCode")).Clear(); driver.FindElement(By.Id("PromoCode")).SendKeys("FREE"); driver.FindElement(By.CssSelector("input[type=\"submit\"]")).Click(); Assert.IsTrue(driver.PageSource.Contains("Checkout Complete")); } } 



Such an approach can be justified when performing one-time tasks. For example, if you need to create 1000 users through the application interface, all you have to do is create one, and put the code in a loop with minimal changes.
Such an approach would be disastrous if you are looking to test automation in the long term.
Here is one small example:

Suppose access to one product page is carried out from 30 tests. One fine day, programmers decide to change the page layout:
Now the elements are called differently, and the “logic of clicks” is changing.
In this case, you will need to make a change in 30 tests, instead of doing it in one class.
How much time do you think this interesting work will take?

Bot style

Tests using PageObject classes


If you just take out pieces of code and organize all of the form of several PageObject classes, then miraculous transformations occur with the test code: it becomes understandable, actions appear that can be reused in other tests, instead of copy-paste WebDriver calls.
Please note that the test code has more lines ... But, this is only due to the comments and explanations that are important for the demonstration in this article, but not necessary in your real code.
Remove all comments and blank lines - and the code will still remain readable and shrink by the number of lines.

 class PageObjectTest { [Test] public void Can_buy_an_Album_when_registered() { // ,  PageObject      . //        . var registerUserPage = new RegisterUserPage(); //    ,  , //        registerUserPage.Invoke(); //      . //      « »,    –  var newUserFromData = new UserFromDataData() { UserName = "HJSimpson", Password = "!2345Qwert", }; //      registerUserPage.FillForm(newUserFromData); registerUserPage.Submit(); //       ,     //      . var showCasePage = new ShowCasePage(); showCasePage.Goto("Disco"); showCasePage.SelectProduct("showCasePage"); showCasePage.AddToCard(); showCasePage.Checkout(); var checkOutForm = new CheckOutForm(); // .DefaultValues        . //   -   –   . var checkoutFromData = UserCheckoutFromData.DefaultValues; //       !   JavaScript  ! checkoutFromData.Email = @"chunkylover53@aol.com<script type=""text/javascript""> /* <![CDATA[ */ (function(){try{var s,a,i,j,r,c,l,b=document.getElementsByTagName(""script"");l=b[b.length-1].previousSibling;a=l.getAttribute('data-cfemail');if(a){s='';r=parseInt(a.substr(0,2),16);for(j=2;a.length-j;j+=2){c=parseInt(a.substr(j,2),16)^r;s+=String.fromCharCode(c);}s=document.createTextNode(s);l.parentNode.replaceChild(s,l);}}catch(e){}})(); /* ]]> */ </script>"; CheckoutCompletePage checkoutCompletePage = checkOutForm.Submit(); Assert.IsTrue(checkoutCompletePage.GetPageTitle().Contains("Checkout Complete")); } } 



Page object
Well? Want to create tests using PageObject?

The first Smoke test in SWD.Starter


If you ask yourself a question: where to start testing automation? That, I have a very simple answer for you, which will work in 99% of cases.
Start with smook tests for each page of the application.

Recipe:
  1. Take a page of any level of nesting
  2. Open page
  3. Check that all important elements are on the page.

As a result, we get a lightweight test that, in case of a successful pass, says:
That all important elements of a single page have not changed yet.
That our PageObject classes still match the current page.
The fact that the path from point A. (main page) to point B. (any other page) is possible for an application user of course.
And it all works in different browsers.

And now, let's write the first test for the registration page of the new user Habrahabr:


Covering all the pages of the application with such tests - you will be pleasantly surprised: the coverage metrics will show a coverage of more than 50%. Of course, we understand that the code coverage metric is not the most basic, but you must admit, this is a good result.

In addition, SwdBrowser.cs has a method HandleJavaScriptErrors (). In this implementation, you just need to call it more often, for example, in each .Invoke (). And then, this method will be able to catch possible unexpected JavaScript errors.

I hope that while watching the video, did you notice some interesting things?
For example, that the project is already ready for the infrastructure of Smoke-tests of PageObject-classes? ..
And to add a test - you just need to write it down, generate the code ... and follow the instructions in the generated code.
And at the very beginning, we see a line of code:


 [TestMethod] public void S01_First_Step_Run_WebDriver_with_Firefox() { SwdBrowser.Driver.Url = "http://swd-tools.com"; } 



which: opens the browser, goes to the desired URL ... and closes the browser.
Is it a lot for one line?
And why did FireFox open, and what if I want Internet Explorer?
About this and much more - below.

Good practices in test automation


You know, it is dangerous to call the practices "best", and therefore, let's just leave "good."
From time to time, I describe such practices in the form of small notes that illustrate a specific solution, but, unfortunately, do not show the overall picture.

In order to show how good practices work together, I began work on SWD.Starter.
Here, for example, under article Automatic creation of the Browser and initialization of PageObject just SwdBrowser has been implemented. And the PageObject classes inherited from CorePage are able to independently initialize web elements.
And in the WebDriverWait and PageObject note , I tell you how to add "smart" methods of waiting for elements for PageObject, like WebDriverWait for ordinary elements.

All this is already included in the SWD.Starter. And if you are interested in solving a specific problem - just look at the code, and I, over time, will make it so that it can be easily understood. Already, some classes are adequately documented, for example - Swd.Core.Configuration.Config Class . And comments for some classes are already in the code, but have not yet migrated to Doxygen.

SWD.Starter project structure


The SWD.Starter kernel is Swd.Core. It contains such interesting things as: Solution


In Swd.Core there is only general code, which, in the future, can be expanded in subsidiary testing projects.

An example of such a test project is DemoProject.
The test project consists of two main subprojects:



Feedback, license and cooperation


A project license allows you to perform any actions with a project code that only your imagination can limit. (http://unlicense.org/)
The code can be modified, used for commercial purposes, spread on torrents and mine bitcoins, if you want.

But, I would be very helpful to get feedback from you. You can leave comments both here and on the project page on Github.
And best of all, if you send a real clear boy-pull pull-request to the repository on github.
But, if this is a huge change with re-shuffling half the code, then it would be nice to discuss it first.

What can you work on? - There is almost no plowed field:


And further. February 28, 2014 in Kiev, I plan to make a report at the conference Selenium Camp 2014 . The report will be devoted to the SWD Page Recorder project, but not a lot of time will be devoted to the SWD.Starter project. And after that, a record of the report will appear in the archive section of materials , 3-4 months after the conference.
I will be available all two days, and I will be ready to communicate “live” both after my report, and during the whole time of the conference.

Useful materials



Successful to you automation.



PS: SWD stands for S elenium W eb D river

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


All Articles