Code & QA

Test execution step by step in details. How things work

Let’s looks at the test from previous section – SearchWithGoogle. Below I’ll try to explain in details how the things are working. Step by step. Let’s go.

0. When an application starts the compiler invokes all static constructors and creates all static variables. These variables are:

Globals.timeoutForPageLoading – timeout in seconds for waiting until a page isloaded. A page must be completely loaded within this period of time, otherwise an exception may be thrown. Not initialized yet.

Globals.timeoutForWaitingElement – timeout in seconds for looking an element on a page. Not initialized.

Globals.timeoutBetweenClicks – timeout in seconds between attempts to click an element. Not initialized.

Report.TestSession – instance of TestSession class which represents the entire summary report. It stores list of test cases (tests) which are to be run under current test session. In the end of test execution this variable is used for composing of summary report.

Report.ReportFolderPath – path to a folder where summary report will be saved. Not initialized.

Report.logFilePath – variable for storing the path to log.txt file where test events will be saved. Not initialized.

Report.doEventLogging – indicates is it necessary to write down all event to log.txt file or not. False by default.

Also on this stage Report() static constructor is invoked. It sets TestSession.StartTime to current time – start time of the test session.

GlobalSetup.testSessionName – name of current test session defined in App.config file:

<appSettings>

. . .

<add key=”testSession” value=”MyTestedApplication_build_001″/>

. . .

</appSettings>

1. Static GlobalSetup.SetUpAssembly() method is invoked.

The method sets values to global variables (Mapping.Extensions.SetGlobals()) and invokes method Report.StartTestSession.

SetGlobals() initializes several global variables:

Globals.timeoutForPageLoading = Int32.TryParse(ConfigurationManager.AppSettings[“timeoutPageLoading”], out temp) ? temp : 60;

Globals.timeoutForWaitingElement = Int32.TryParse(ConfigurationManager.AppSettings[“timeoutElementLoading”], out temp) ? temp : 30;

Globals.timeoutBetweenClicks = Int32.TryParse(ConfigurationManager.AppSettings[“timeoutBetweenClicks”], out temp) ? temp : 1;

Report.doEventLogging = ConfigurationManager.AppSettings[“doEventLogging”] == “true”;

Globals.applicationURL = ConfigurationManager.AppSettings[“applicationURL”];

Values for the variables are taken in App.config file (or default values are used if a value is not defined).

In my case the variables are equal to:

timeoutForPageLoading = 20;

timeoutForWaitingElement = 10;

timeoutBetweenClicks = 1;

doEventLogging = true;

applicationURL = “http://myapplication.com”;

because in App.config file I have the following:

<add key=”timeoutPageLoading” value=”20″/>

<add key=”timeoutElementLoading” value=”10″/>

<add key=”timeoutBetweenClicks” value=”1″/>

<add key=”doEventLogging” value=”true”/>

<add key=”applicationURL” value=”http://myapplication.com”/>

StartTestSession () method initializes ReportFolderPath and logFilePath variables and sets values to TestSession.Description and TestSession.Name fields. It also creates new folder with ReportFolderPath path and creates new text file named log.txt inside the folder. When the file is created the method opens it for writing and put new line in the file via Log(string message) method. Log method opens the file, write its parameter value into it, saves and releases it.

public static void Log(string logMessage)

{

if (doEventLogging)

using (StreamWriter w = File.AppendText(logFilePath))

{

w.WriteLine(“{0}”, logMessage);

}

}

If you manually open the file on this stage you will see there the only one note:

Start test session: MyTestedApplication_build_001.

After this step I have the following:

· all static variables like timeoutForPageLoading, timeoutForWaitingElement, timeoutBetweenClicks, doEventLogging, applicationURL are initialized

· ReportFolderPath is initialized. Report folder is created

· fields of Report.TestSession are initialized

· log.txt file is created with new line added

2. After the test is started the first invoked method is BaseTest.Setup().

If browser type specified in App.config file is “Android” it invokes StartProcess method which starts cmd.exe program which invokes selendroid jar file in Java environment. Then the method initializes IWebDriver driver and WebApplication TestedApplication variables:

[SetUp][TestInitialize]

public void Setup()

{

if (ConfigurationManager.AppSettings[“browserType”] == “Android”)

StartProcess(“cmd.exe”, “java -jar selendroid-standalone-0.15.0-with-dependencies.jar”);

driver = SetUpDriverInstance(ConfigurationManager.AppSettings[“browserType”]);

TestedApplication = new WebApplication(driver);

}

In my case SetUpDriverInstance method returns an instance of FirefoxDriver with custom profile. These setting are taken from App.config file where the following is defined:

<appSettings>

<add key=”browserType” value=”Firefox”/>

</appSettings>

and

<FirefoxSettings>

<add key=”dom.ipc.plugins.enabled” value=”true” />

<add key=”browser.startup.homepage” value=”http://google.com” />

<add key=”app.update.interval” value=”86400″ />

</FirefoxSettings>

Then the Application variable is initialized as well:

TestedApplication = new WebApplication(driver);

In the constructor of WebApplication class you can see that its field Driver is set with the value of driver variable initialized above and private field _isNew is set to true. _isNew indicates that the TestedApplication is just initialized and is actually new – no actions are still performed with it or within it.

After the step 2 there are:

· new Firefox browser window is opened with google.com page loaded in it (browser.startup.homepage node value of App.config file)

· variables driver and TestedApplication are initialized and ready for usage

3. SearchWithGooglel() test method is started.

First of all inner constant variables const string searchTerm1 and const string searchTerm2 are created. The variables are used in the test for verification of targeted page title.

Then testScope dictionary is created and filled up with values:

var testScope = new Dictionary<string, string> {

{ “Perform search with ” + searchTerm1 + ” term on New tab page”, “title of the page is ” + searchTerm1 + ” – Google Search” },

{ “Perform search with ” + searchTerm1 + ” ” + searchTerm2 + ” term on New tab page”, “Title of the page is ” + searchTerm1 + ” ” + searchTerm2 + ” – Google Search” },

{ “Close New tab page”, “Home page is displayed” }};

testScope is the description of the test flow in format <description, expected

result>. It is used for reporting.

On step 3 stage the test has started.

4. StartTestCase method invocation.

Report.StartTestCase(GetType().Name, MethodBase.GetCurrentMethod().Name, “Verification of search with Google”, testScope);

The method creates new anonymous instance of TestCase type and adds it to TestSession variable. Further this instance will be added to the list of test cases of the TestSession and used for creation of summary report.

Method parameters:

· GetType().Name is the name of current class. In my case it is TestingWithSelenium. This is also the name of test collection in summary report.

· MethodBase.GetCurrentMethod().Name is the name of current method (in other words the name of current test) – SearchWithGoogle

· “Verification of search with Google” is a short description of the test

· testScope – description of the test flow (see above)

On this step:

· Current test case instance is added to current test session one.

· Several new lines are added to log.txt file – the name of test case and its scope. Now it contains the following:

Start test session: MyTestedApplication_build_001

Start test case: SearchWithGoogle, Verification of search with Google,

Test collection: TestingWithSelenium

Test case scope:

Perform search with jobs term on New tab page – title of the page is jobs – Google Search

Perform search with jobs steve term on New tab page – Title of the page is jobs steve – Google Search

Close New tab page – Home page is displayed

5. Run step

Report.RunStep(“Step 1: Search with ” + searchTerm1 + ” term”);

Method RunStep creates new step and adds it to current test case. It takes a string as a parameter. The string value is used as a tooltip (not description) of the step. The step (its description and other properties – start time, status) is displayed in summary report on the current test case’s page.

In the beginning the RunStep invokes SaveCurrentStep() method which must save current step as new item of TestSession.CurrentTestCase.TestSteps list but since there is no current step yet (this step is the first) there is nothing to save. That’s why SaveCurrentStep() does nothing on this stage:

if (TestSession.CurrentTestCase.CurrentStep == null) //True

return;

After that RunStep checks if there is a description for the step in TestSession.CurrentTestCase.TestScope dictionary. Index of current step is 0 (it is the first step of the test), so there should be a note in the dictionary with index 0 as well. Basing on this isTestScopeValid variable is initialized.

Then TestSession.CurrentTestCase.CurrentStep instance is initialized as new TestStep with new values.

Finally index of current step is incremented and new line is added to log.txt file.

summary: new step is added to current test case.

6. Start of testing.

TestedApplication.NewTabPage.TextboxSearch.TypeText(searchTerm1);

This is pretty simple line at first sight but there are number of actions performet behind the scene.

At the moment TestedApplication variable is already created and initialized (step 2) but NewTabPage property is still null. Since it is represented as WebApplication’s class property it should be initialized when it is referred to. Invocation of WebApplication.NewTabPage (re)calculates NewTabPage NewTabPage property:

public NewTabPage NewTabPage

{

get

{

if (_isNew)

Open<NewTabPage>();

if (!IsValid || _newTabPage == null)

{

_newTabPage = new NewTabPage(Driver) { Name = “New tab” };

IsValid = true;

}

return _newTabPage;

}

}

In the beginning _isNew is checked. At the moment the application is actually newly started and no page is loaded yet. Therefore Open<NewTabPage>() method is invoked. Its input parameter is of NewTabPage type, hence the following part of the code will be executed:

else if (typeof(T) == typeof(NewTabPage))

{

Open<HomePage>();

Report.AddInfo(“Navigating to New tab page”);

_homePage.MenuItemNewTab.Click();

_newTabPage = NewTabPage;

}

The code above describes steps necessary for loading New Tab page – to open Home page first and to click New Tab menu item on the Home page. As you can see the method invokes itself one more time but with another input parameter HomePage. This second invocation of the Open<T> method adds necessary information to the report (and to the log.txt) and navigates the driver to the application start URL:

if (typeof(T) == typeof(HomePage))

{

Report.AddInfo(“Navigating to Home page”);

Driver.Navigate().GoToUrl(Globals.applicationURL);

_homePage = HomePage;

}

_homePage = HomePage line calculates WebApplication.HomePage property and invokes HomePage class constructor. HomePage is a child of MasterPage which inherits WebPage class. Therefore WebPage constructor is invoked first where WaitUntilIsLoaded method starts. The method invokes IsLoaded property of HomePage class which invokes MasterPage.IsLoaded property and calculates Paragraph_1 text element. MasterPage.IsLoaded finds LabelTitle, MenuItemHome and IframeInnerContent elements in the browser and returns their properties IsDisplayed. If all the elements are dispayed (MasterPage.IsLoaded == true) then HomePage.IsLoaded looks for Paragraph_1 element and verifies its IsDisplayed property. When HomePage.IsLoaded is true WaitUntilIsLoaded methods finishes its work. At this point _homePage variable is initialized.

On this stage Home page of the application is displayed in the browser window. Report.AddInfo(“Navigating to New tab page”); message is added to the report and _homePage.MenuItemNewTab.Click(); line is executed. This line has a lot of different actions in background as well.

At the moment _homePage is a reference to an instance of HomePage class and it is already initialized. So the next step of code execution is referring to MenuItemNewTab property which represents New Tab link in the left-side navigation menu panel. MenuItemNewTab is of WebLink class and is calculated in the same way as menu item MenuItemHome. Actually both items MenuItemHome and MenuItemNewTab belongs to MasterPage class but since they are public and HomePage is a child of MasterPage, the MenuItemNewTab is invoked as HomePage class property. The property returns an instance of WebLink.

After MenuItemNewTab is initialized (appropriate IWebElement is found and all WebLink class fields are filled with values) Click() method of WebLink class is invoked.

The method clicks on New Tab menu item. Then new window\tab is opened and New tab page starts loading into it. Method Click() recognizes that number of opened windows\tabs is changed (that means that clicking was successful), switches the Driver to new tab\window and finishes the work.

_newTabPage = NewTabPage line makes _newTabPage variable being a reference to new instance of NewTabPage class. It invokes NewTabPage constractor. Further actions are similar to those which has been executed during HomePage constructor invocation:

WebPage() -> WaitUntilIsLoaded() -> NewTabPage.IsLoaded -> NewTabPage()

At the moment there are two tab or windows opened in the browser. Home page is displayed on one of the tabs, the second shows New Tab page. The driver is switched to the second window.

I want to remind that currently executed line of the test is

TestedApplication.NewTabPage.TextboxSearch.TypeText(searchTerm1);

and only TestedApplication.NewTabPage part of it is calculated now.

Execution flow of this part of code is the following:

TestedApplication.NewTabPage

Open<NewTabPage>()

Open<HomePage>()

Driver.Navigate().GoToUrl(Globals.applicationURL)

HomePage constructor

MasterPage constructor

WebPage constructor

WaitUntilIsLoaded()

HomePage.IsLoaded

MasterPage.IsLoaded

HomePage.IsLoaded

WaitUntilIsLoaded()

WebPage constructor

MasterPage constructor

HomePage constructor

Open<HomePage>()

HomePage.MenuItemNewTab

Click()

HomePage.MenuItemNewTab

NewTabPage constructor

WebPage constructor

WaitUntilIsLoaded()

NewTabPage.IsLoaded

WaitUntilIsLoaded()

WebPage constructor

NewTabPage constructor

Open<NewTabPage>()

7. As far as TestedApplication.NewTabPage is already instanciated the

TextboxSearch.TypeText(searchTerm1);

part of code may be executed. It is TextboxSearch property of NewTabPage class. When the property is recalculated the following line is executed:

if (_searchForm == null || !WebApplication.IsValid)

On the previous step when NewTabPage.IsLoaded property has been executed the TextboxSearch property has been calculated as well. Therefore _searchForm variable has been initialized with new instance of WebTextbox class. So at the moment _searchForm is not null.

WebApplication.IsValid is currently true so far as its value has been changed inside WebApplication.NewTabPage property.

Therefore the expression above is not positive and the code inside if opetator is not executed. It means that no new element should be created or recalculated, WebApplication.NewTabPage.TextboxSearch property just returns value of _searchForm variable which has been calculated on previous step and is still being valid.

8. TypeText(searchTerm1); method of TextboxSearch element is invoked. The method put value of searchTerm1 variable into search textbox on the New Tab page. TypeText(string message) is described in details in Textbox section above.

9. The rest steps of the test are executed in the same manner as described above. Surely, details are defferent but general approach is the same. So I don’t see any sence in wide description of the same actions number of times consequently. If you want to see details you want to explore the code or run tests in debug mode.

10. When the test finished its work (all the test line of code are executed or an exception has been thrown) the Teardown() method located in BaseTest class starts working. It invokes Report.FinishTestCase() method which saves current test step and calculates test case duration. Current test case is saved as well and adde to the list of test cases – TestSession.TestCases.

Then the driver is disposed – all browser windows\tabs are closed, the instance of IWebDriver is destroyed.

11. The next test is started being executed. New instances of IWebDriver and WebApplication are created, method BaseTest.SetUp() is invoked again, then test method is executed and finally BaseTest.TearDown() destroys the IWebDriver. It repeats until all started test methods are executed.

12. When the testing over TearDownAssembly() method is invoked. It composes and saves to local drive summary report (Report.SaveReport()) and sends it by email (Report.SendReportByEmail(subject, addresses, body)).

That’s it.

[row]
[column lg=”6″ md=”12″ sm=”12″ xs=”12″ ]
Assertion [/column]
[column lg=”6″ md=”12″ sm=”12″ xs=”12″ ]
Table Of Content
[/column]
[/row]

Leave a Reply