Hello, dear Habroskoobschestvo! I want to share my way of developing and organizing the writing of automated tests based on Selenium WebDriver 2.x in the C # programming language.
I must say at once that many theses, principles and methods of development were not invented by me (and, probably, not by my teachers).
Perhaps this post will help those who are just beginning to engage in automated testing of Web applications.
Training
To develop automated tests using Selenium, we need the following components:
Development environment, in our case Visual Studio;
NUnit program for automatic running of written tests (download can be found here:
www.nunit.org/index.php?p=download );
Mozilla Firefox browser with two plugins installed for it: FireBug and FirePath (not used in this article).
Setting up the development environment
To write automated tests, you need to create a new project of the
Class Library type (you can also create a console application, but not in our case). It is advisable to give it a name that is associated with the name of the project under test. Also, it is desirable to create a test project in the solution itself with the project under test.
After creating a test project, you need to connect 3 special test libraries to it:
NUnit (nunit.framework) - a library for directly running automated tests (not only for Selenium);
WebDriver + WebDriver.Support - directly to the Selenium library.
You can connect libraries to a test project via NuGet or manually by downloading the latest version from
code.google.com/p/selenium/downloads/list .
')
Building a test project architecture
Base class
Before writing the automated tests themselves, we first need to create helper classes.
In the test project we will add a new class and name it
SeleniumTestBase.cs (it is possible and in another way). Let's declare this class as
public abstract , since all test classes will be inherited from this class in the future. You also need to add the
[TestFixture] attribute to the class, which indicates the class as a test class. In this class, those fields and methods are declared that are necessary for passing any test.
In this class, be sure to declare the field:
protected IWebDriver Driver ; Is an instance of the browser driver that is created before the test (s) is run. There are 4 types of drivers (+ several under development): FirefoxDriver, InternetExplorerDriver, ChromeDriver, HtmlUnitDriver (cross-platform virtual browser without a graphic component).
We will also declare 4 methods in the class (although some may be empty or \ and are not defined at all):
public void TestInitialize () with the attribute [TestFixtureSetUp] - the method with this attribute will be called once before running the tests from any test class (if there are several classes, then the method will be called before the tests from the first class, then before the methods of the second class and so Further). In this class, it is desirable to assign a specific value to the Driver variable, for example:
Driver = new FirefoxDriver();
public void TestCleanup () with the [TestFixtureTearDown] attribute - the principle of operation as in the previous method, but only after the test class is run. In this class, it is advisable to close the browser driver, since when you run the next test class, a new instance of the browser driver will be created (as a result, many instances of the browser driver may remain open, and the RAM is not rubber):
Driver.Quit();
public void OneTearDown () with the [TearDown] attribute - the method is called after running each individual test. In this method, for example, you can clean your browser’s cookies before each new test:
Driver.Manage().Cookies.DeleteAllCookies();
public void OneSetUp () with the [SetUp] attribute - the method is called before running each individual test. For example, you can expand the browser window to full screen when running the test (irrelevant for HtmlUnitDriver):
Driver.Manage().Window.Maxmize();
Wrapper
When writing different tests (even in different classes), code duplication is possible (more precisely, it will definitely be). To avoid clutter in test classes, it is useful to create a
static class Wrapper helper class into which we put code duplication into separate methods.
Most of the tests will start with the same line of code:
Driver.Navigate().GoToUrl(<>);
Therefore, it is logical in the Wrapper class to define the
private static string _domain field in which we will write the URL we need, as well as the method for obtaining this URL:
A piece of code public static string GetUrl() { _domain = "http:\\www.yandex.ru"; return _domain; }
The difference between
Wrapper.cs and
SeleniumTestBase.cs is that the first one declares methods that are called inside tests (and even inside SeleniumTestBase), and the second one methods that are called before or after the tests.
After creating auxiliary tests, we are already creating regular test classes.
Thus, the architecture of the test project looks like this:

Example of writing a test
Create a new test class and name it TestClass1.cs. First, we will write a simple test code, then we will explain what line of code does.
GoTo Yandex [Test, Timeout(10000)] public void Test1() { Driver.Navigate().GoToUrl(Wrapper.GetUrl()); Assert.IsTrue(Driver.Title == ""); }
[Test] is an attribute that determines that this method is a test method.
Timeot (int millSec) - works only with the Test attribute - indicates the maximum allowable number of milliseconds to pass the test. If the timeout is exceeded, the test drops immediately (even at run time) and is considered unsuccessful.
public void - the test should have just such an access modifier and should not return any value for the test to work correctly.
Driver.Navigate (). GoToUrl (Wrapper. GetUrl ()) - the browser driver will open the Yandex page for us.
Assert.IsTrue (Driver.Title == "Yandex") - direct check, in this case, the test checks that the page title is "Yandex", in this case the test is considered passed, otherwise the test is not passed.
Running tests
To get rid of our tests, we need a specially created program for this -
NUnit (download link at the beginning of the document).
Let's compile our test project. At the output we have a file type .dll
Run NUnit. Next, click File-Open Project. A window will appear in which we must find and select the newly compiled library.
After loading the library into the program, on the left we will see a tree of test classes with our tests. In this tree, you can select a separate test, class or all classes of tests, then click the Run button - and the tests will start running. Run can be stopped at any time by pressing the Stop button.
After passing the tests, their color will change in the tree: green - the test has passed, red - the test has fallen, yellow - the test will not pass for any reason (no drop), gray - the test has not yet started. Under the buttons there is a window with a log of dropped tests, which can be used to find out why a particular test fell.
Additional Information
The fastest browser driver is ChromeDriver. Guess the slowest.
For ChromeDriver and InternetExplorerDriver, you need to download an additional driver application and put it in the project directory.
Also in the tests used attributes:
[TestCase (var v1, ..., var vOver9000)] - used if the test has to
iterate over several possible input data. Before the test, you can write any number of test cases. To work correctly, the test method must pass as many parameters as the variables are written in the test case. Test cases should be identical in composition (it is not possible to write test cases with 1 variable, and then with 2) before the test. Example:
TestCase () [Test, Timeout(10000)] [TestCase("", 1)] [TestCase("", 2)] [TestCase("", 3)] [TestCase("", 4)] [TestCase("", 5)] public void Test2(string str, int days) { }
An alternative to test cases are the attributes
[Range ()] and [Values ​​()] . But unlike test cases, these attributes are written with the arguments passed.
Range is better to use for enumerated values,
Values - for non-enumerated. Also, the number of tests to be run will be equal to the number of all combinations of variables. Example:
Range + Values [Test] public void Test3([Range(0,3)]int a, [Values(“0”, “1”, “2”, “3”)]string b) { Assert.IsTrue(a.ToString() == b); }
There are 16 tests and only 4 of them will pass.
Tips
In writing automated tests, one should adhere to the concept of
AAA - Arrange-Act-Assert :
Arrange - the necessary settings and actions before the test itself;
Act - directly test;
Assert is a block for checking conditions of the type “expected result == current result”.
Take the example above by rewriting it a bit:
AAA Begin [Test, Timeout(10000)] public void Test1() { Driver.Navigate().GoToUrl(Wrapper.GetUrl()); var title = Driver.Title; Assert.IsTrue(title == ""); }
Here Arrange is a transition by url, Act is a calculation of the title of the page, Assert is a check of the condition “expected result == current result”.
For readability, the test can be rewritten as follows:
AAA Complete [Test, Timeout(10000)] public void Test1() {
Take a habit: one test - one Assert. It is advisable not to break at all or break in extreme cases (with a large number of checks in the test, the readability of the code is reduced).
Many selectors in the code can be repeated several times. It is better to make them into separate string constants, since the layout of the site can constantly change, and with it the selectors. Then, when changing the selector, it will have to be changed only in one place, and not in 20 places throughout the project.
Sometimes the first run of the test can be timed out, since when the browser driver is first launched, a long page load is possible. It should be increased in some tests timeouts.
By quality standards, the timeout for loading the page in the browser is 10 seconds. Set a timeout for finding an item on the page in 11 seconds (maximum 12).
With some elements on the page it is impossible to interact using Selenium + C #. In this case, use JavaScript + jQuery to access such page elements. Example:
JavaScript + jQuery protected IJavaScriptExecutor _jsExecutor; var script = @"var c = $('table>tbody:visible').last();" + "c = c.find(\"tr:nth-child(2)\");" + "c.find(\"td:nth-child(1)\").click();"; _jsExecutor = (IJavaScriptExecutor)Driver; _jsExecutor.ExecuteScript(script);
For the convenience of running tests (NUnit is not the most convenient thing), you can additionally install the ReSharper plugin in Visual Studio, which allows you to run tests as well as watch the results of the run. But unlike NUnit, ReSharper is a paid add-on.
Conclusion
This article, unfortunately, cannot be considered a guide to writing Selenium tests, since the methods and methods for testing web applications are not described here. In particular, the Assert class for checking conditions and the Selenium methods for searching elements on a Web page. Another article will be devoted to this.
I hope that the approach I have outlined will be used by someone to write their automated tests.
Thanks for attention!