Combine automation technologies working with complicated desktop applications

Author: Alfonso Alarcón

This is a reality for automated testing engineers! This is the fact! In some occasions, it is practically impossible to generate functional testing on the user interface (UI) of some desktop applications.

Normally, the reason is that the desktop application is based on a code that is written in languages that are not recognized by spy tools or the recognition tool of the selected automation technology. This is very usual in legacy code that is created far of actual technologies.

The situation is more tragic when tools that are in principle powerful, such as the Coded UI Test tool of Visual Studio or HP UFT (to mention just two examples), fail!! In summary, it is a catastrophic situation for automated testing engineer especially when UI testing is essential and required by QA. What should you do? Fortunately, there are solutions.

The most logical solution is to combine different automation technologies (hybridize). I suggest using as the basis a solution of Visual Studio (a console project is enough) and over it work on other technologies. I mention two:

  • AutoIT: Autoit (https://www.autoitscript.com/site/autoit/) is a freeware software to provide automated testing on windows GUI.  You can work with the method of the class AutoItX3Lib. To do it you must download and install AutoIt from https://www.autoitscript.com/site/autoit/ and add the reference of AutoItX3Lib to the solution. Please, also read about https://autohotkey.com/.
  • White: It is a very interesting solution to extend the functionalities of Visual Studio to provide automation testing. It must be added via nuget: https://www.nuget.org/packages/TestStack.White/

It is noteworthy that it is not required any payment version of Visual Studio. With Visual Studio Express or Community versions is enough. In this scenario, you can provide a reliable automation without money expenses.

But possible your company desires to expend a lot of money in automation testing in this case I recommend Ranorex (http://www.ranorex.com/). This is a powerful and complete tool that can provide work on web and GUI, and also in mobiles devices in both android and iOS. My suggestion is to combine Ranorex with Visual Studio (again combine technologies!) for a definite automated testing experience.

Finally, in an ending case Microsoft indicates an extension of the of the Code UI test tool to provide automated solutions where the coded UI tool does not arrive. But this solution is only for heroic automated testing engineers! I provide the next URLs:

https://msdn.microsoft.com/en-us/library/ff398055.aspx

https://msdn.microsoft.com/en-us/library/hh552522.aspx

https://blogs.msdn.microsoft.com/visualstudioalm/2011/10/28/coded-ui-test-extension-for-3rd-party-controls-the-basics-explained/

In conclusion, there is always a hope to automate an inaccessible UI! And remember that the best solution is always combining different automated testing technologies.

 

Advertisements

Automated testing for web application with Visual Studio CodedIUTest without recordings

Author: Ferran Sánchez

If you want to do testing on a web application you can have an alternative with CodedIUTest tool of Visual Studio but without recordings. In this methodology you can use objects such as HtmlHyperlink, HtmlInputButton and HtmlEdit to access to their characteristics directly (see https://automatedtestingtools.wordpress.com/2016/04/19/strategy-to-get-automated-testing-without-recording-actions).

It is known that the recording tool of Visual Studio provides internet explorer as default browser. The key point to work with a different browser is to initialize a static variable BrowserWindow to select the browser and launch web page. For example, if you want to work with Chrome you must write: BrowserWindow.CurrentBrowser = “chrome”;

After that, you can begin the automated testing web. The following example shows this possibility providing data source like a .csv file for data input parameters.

Also, to work with a different browser you must take into account the next preconditions:

1 – Configuration of “Selenium Components for Coded IU Cross”: https://visualstudiogallery.msdn.microsoft.com/11cfc881-f8c9-4f96-b303-a2780156628d/

2 – Troubleshoot: If you have some error when you run tests on Chrome browser, you can download another version on http://selenium-release.storage.googleapis.com/index.html

[CodedUITest]
public class CodedUITest1
{
	// Static var for launch the browser window
	BrowserWindow browser;
	public CodedUITest1()
	{
	}
	// Initialize browser and web page
	[TestInitialize()]
	public void MyTestInitialize()
	{
		BrowserWindow.CurrentBrowser = "chrome";
		browser = BrowserWindow.Launch(new Uri("http://www.amazon.es"));
		browser.Maximized = true;
		browser.CloseOnPlaybackCleanup = false;
	}
	[DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "|DataDirectory|\\dataAmazon.csv", "dataAmazon#csv", DataAccessMethod.Sequential), DeploymentItem("dataAmazon.csv"), TestMethod]
	public void CodedUITesAmazonHandcoding()
	{
		// Assert Vender tab string
		HtmlHyperlink VenderTabString = new HtmlHyperlink(browser);
		VenderTabString.SearchProperties.Add(HtmlHyperlink.PropertyNames.InnerText, "Vender");
		Assert.AreEqual(
"Vender", VenderTabString.InnerText.Trim());

		HtmlHyperlink VenderTab = new HtmlHyperlink(browser);
		VenderTab.SearchProperties.Add(HtmlHyperlink.PropertyNames.InnerText, "Vender");
		Mouse.Click(VenderTab);
		Playback.Wait(1000);
		// Assert "Vender tus productos" string
		HtmlSpan labelVender = new HtmlSpan(browser);
		labelVender.SearchProperties[HtmlSpan.PropertyNames.InnerText] = "Vende tus productos en Amazon";
		Assert.AreEqual("Vende tus productos en Amazon", labelVender.InnerText.Trim());
		// Assert Ofertas tab string
		HtmlHyperlink OfertasTabString = new HtmlHyperlink(browser);
		OfertasTabString.SearchProperties.Add(HtmlHyperlink.PropertyNames.InnerText, "Ofertas");
		Assert.AreEqual("Ofertas", OfertasTabString.InnerText.Trim());
		Playback.Wait(1000);

		// Assert Ayuda tab string
		HtmlHyperlink AyudaTabString = new HtmlHyperlink(browser);
		AyudaTabString.SearchProperties.Add(HtmlHyperlink.PropertyNames.InnerText, "Ayuda");
		Assert.AreEqual("Ayuda", AyudaTabString.InnerText.Trim());
		HtmlHyperlink AyudaTab = new HtmlHyperlink(browser);
		AyudaTab.SearchProperties.Add(HtmlHyperlink.PropertyNames.InnerText, "Ayuda");
		Mouse.Click(AyudaTab);
		Playback.Wait(1000);
		// Verify "contraseña" wrong
		HtmlHyperlink IdLink = new HtmlHyperlink(browser);
		IdLink.SearchProperties.Add(HtmlHyperlink.PropertyNames.Id, "nav-link-yourAccount");
		Mouse.Click(IdLink);
		//Assert "Contraseña" string
		HtmlLabel labelCont = new HtmlLabel(browser);
		labelCont.SearchProperties[HtmlLabel.PropertyNames.InnerText] = "Contraseña";
		Assert.AreEqual("Contraseña", labelCont.InnerText.Trim());

		HtmlEdit MailInput = new HtmlEdit(browser);
		MailInput.SearchProperties.Add(HtmlEdit.PropertyNames.Id, "ap_email");
		MailInput.Text = TestContext.DataRow["user"].ToString().Trim();
		HtmlEdit PasswordInput = new HtmlEdit(browser);
		PasswordInput.SearchProperties.Add(HtmlEdit.PropertyNames.Id, "ap_password");
		PasswordInput.Text = TestContext.DataRow["password"].ToString().Trim();

		HtmlInputButton IniciarButton = new HtmlInputButton(browser);
		IniciarButton.SearchProperties.Add(HtmlInputButton.PropertyNames.Id, "signInSubmit");
		Mouse.Click(IniciarButton);
		Playback.Wait(10000);
	}

Strategy to get automated testing without recording actions

Author: Alfonso Alarcón

Many times the usual work environment in large automated testing projects is under a continuous integrated development process. This implies that both development and automated testing processes are done in parallel.  In this scenario the most common problems are related with test cases that fail as a consequence of changes in the functionality (by part of developers) and not as a consequence of finding bugs in this functionality (that is the final purpose). For this reason providing a good treatment and maintenance of controls (different structures that conforms the functionalities of an application or web such as comboboxes, menubars, tablegrids, buttons, winedits, among others) is the key point.

The most extended way of working (and the easiest) in automated testing is recording actions. All the specialized software in this field such as Visual Studio, HP UFT, Ranorex Studio, SeeTest, Squish… are their own recording tools. But this strategy presents manifest problems, basically:

  • Maintenance: When we have a great quantity of recorded actions they must be reviewed one by one when changes in the application are common.
  • Unproductive recording: In some situations controls are recorded one by one providing a great quantity of recorded actions. For example, if you want to get the information of a menu (for example, the menu file in an application) the most easily solution is to record all items one by one spending a great quantity of time. See the post https://automatedtestingtools.wordpress.com/2016/04/17/how-to-get-menu-elements-from-the-parent-element
  • Unproductive strategy: Usually in our daily work we focus our attention only in the part of the functionality under test without any global vision.

To surpass these problems it is recommended a strategy based on change the way of thinking for understand the software that you are testing from a general vision. The strategy has a general purpose and can be used for all specialized software.  It is based on the next points:

  • Improve the maintenance: Get the information from the parent and from it obtain all the children’s. With this way of working you only need to capture the UI control of the parent of the menu and from it to get all the items of the menu reducing the spending time (in reference to recording action method) and increasing the maintenance.
  • Avoid recording actions: Store the information related with controls instead of record it. See post How to get UI Controls with Coded UI Test Builder without recording actions
  • Smart strategy: First analyze how many controls types have the UI and next start working.

Also, to support the strategy proposed it is suggested to provide a layer structure since this way of working provides the next advantages:

  • The division of the solution into separate layers improves the maintenance.
  • Changes in one part of the solution should impact in other parts minimally.
  • Certain components must be reusable in different modules.

Therefore, the most basic structure can be schematized as:

1

Uimap

The lowest layer of abstraction, it is the basis of the system. It represents a Map of the user interface (UI) ordered in a tree structure. Here, it is to possible visualizing the UI Controls.

FuctionalActions

This layer presents a set of classes to deal with UI Controls stored in UIMap. Whether with or without recording actions the associated information about controls is stored in the UI Control Map (see post How to get UI Controls with Coded UI Test Builder without recording actions). With the strategy presented here we don’t have created the method that manipulates the action (for example click a menu item) and therefore the creation has to be done a posteriori (see post https://automatedtestingtools.wordpress.com/2016/04/15/how-to-get-menu-elements-from-the-parent-element).

For example in the particular case of .net in Visual Studio, the layer structure can be:

2

TestCripts

It is the most external layer where are implemented the test cases using methods created basically in the FunctionalActions layer.

Utilities

Here, different classes that can be used transversally in all layers are created. Here, it is recommended to create a class to store the constants that can be used as key in dictionaries, classes to access to XML files, etc….

This post is only an approach to review a strategy  that is well known in automated testing from a general point of view, independent of the technology used. To complete the explanation other posts have been provided and will be provided in the future.

 

How to create an Ent-To-End Test with Selenium WebDriver, TestNG project and Jenkins (CI)

Author: Ferran Sánchez

Objective:

Create an End-To-End test using Selenium WebDriver with Java, TestNG project and running them to Jenkins (CI) periodically every day.

Preconditions:

  1. Download Eclipse IDE and Extract -> eclipse luna http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/junosr2
  2. Download Java (jdk) and Install http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html.
  3. Download the followings selenium items from http://www.seleniumhq.org/download/
  • Selenium Standalone Server
  • Selenium Html Runner.
  • The Internet Explorer Driver Server
  • Selenium Client & WebDriver Language Bindings for “Java” -> recommend “selenium-java-2.47.1”
  • Google Chrome Driver (latest version).
  • Install TestNG -> Help > Install New Sofware > TestNG http://beust.com/eclipse/
  • Add the libraries to “scr” project  > Add External JARS…:
  • selenium-server-standalone-2.47.1.jar
  • All files from C:\SeleniumDoc\Seleniumtests\JAR\selenium-java-2.47.1\selenium-2.47.1\libs folder
  • selenium-java-2.47.1.jar and selenium-java-2.47.1-srcs.jar

Steps:

We have a Java project “FirstTestNgProject” with 3 TestNG classes.

1.- First class name: FirstClassTestNg. It contains the following tests:

  • Launch Chrome
  • Get amazon.es webpage. Verify url and return passed/failed on console.
  • Verify the webpage title and return passed/failed on console.
  • Verify linktext and navigation of “Ofertas” and “Ofertas seguidas” links.
  • Navigation to Amazon main webpage. Verify the title and return passed/failed on console.
public class FirstClassTestNg {
	public static WebDriver driver;// driver declaration for run browser in all methods

	// Quit browser
	@AfterClass
	public void closeBrowser(){
	driver.close();
	}
	// Launch amazon.es main page and verify the current url
	@Test(priority=1)
	public void LaunchAmazonMain() throws InterruptedException {
	System.setProperty("webdriver.chrome.driver", "C:/SeleniumDoc/chromedriver_win32/chromedriver.exe");
	driver = new ChromeDriver();
	driver.manage().window().maximize();
	driver.get("https://www.amazon.es");
	Thread.sleep(5000);
	String Url = driver.getCurrentUrl();
	System.out.println(Url);
	if (Url.equals("https://www.amazon.es/")){
	System.out.println("Amazon current URL - Passed");
	}
	else {
	System.out.println("Amazon current URL - Failed");
	}
	}
	// Verify the web page title and current url are correct. It's shown a message
	@Test(priority=2)
	public void testAmazonMainPage() throws InterruptedException{
	String PageTitle = driver.getTitle();//String url = driver.getCurrentUrl(); -> it is other option.
	System.out.println(PageTitle);
	if (PageTitle.equals("Amazon.es: compra online de electrónica, libros, deporte, hogar, moda y mucho más.")){
	System.out.println("Amazon Application Launched - Passed");
	}
	else {
	System.out.println("Amazon Application Not Launched - Failed");
	}
	}
	// Verify linkText and url
	@Test(priority=3)
	public void verifyLinkText() throws InterruptedException{
	Assert.assertEquals(driver.findElement(By.id("nav-your-amazon")).getText(), "Mi Amazon.es");
	// Verify linkText "Ofertas"
	String OfertasLink = driver.findElement(By.linkText("Ofertas")).getText();
	Assert.assertEquals(OfertasLink, "Ofertas");
	driver.findElement(By.linkText(OfertasLink)).click();
	Thread.sleep(9000);
	// Verify linkText "Ofertas seguidas"
	String OfertasSeguidas = driver.findElement(By.linkText("Ofertas seguidas")).getText();
	Assert.assertEquals(OfertasSeguidas, "Ofertas seguidas");
	driver.findElement(By.linkText(OfertasSeguidas)).click();
	Thread.sleep(9000);
	Assert.assertEquals(driver.findElement(By.className("gbh1-bold")).getText(), "Ofertas que estás siguiendo");
}
	@Test(priority=4)
	public void verifyReturnHome() throws InterruptedException{
	driver.navigate().to("https://www.amazon.es");
	Thread.sleep(9000);
	String PageTitle = driver.getTitle();//String url = driver.getCurrentUrl(); -> it is other option.
	System.out.println(PageTitle);
	if (PageTitle.equals("Amazon.es: compra online de electrónica, libros, deporte, hogar, moda y mucho más.")){
	System.out.println("Amazon Application Home page - Passed");
	}
	}
}

2.- Second class name: SecondClassTestNgIe. It contains the following tests:

  • Launch Iexplorer browser
  • Get amazon.es webpage. Verify url and return passed/failed on console.
  • Navigate to gmail.com webpage. Verify the title and return passed/failed on console.
  • Return to back webpage. Verify the text “Mi  amazon.es”.
public class SecondClassTestNgIe {
	public static WebDriver driver;// driver declaration for run browser in all methods

	// Launch amazon.es main on IExplorer browser
	@Test
	public void LaunchAmazonMain() throws InterruptedException {
	// Launch webDriver
	System.setProperty("webdriver.ie.driver", "C:/SeleniumDoc/IEDriverServer_Win32_2.53.1/IEDriverServer.exe");
	WebDriver driver = new InternetExplorerDriver();
	driver.manage().window().maximize();
	// Amazon Main Page
	driver.get("https://www.amazon.es");
	Thread.sleep(5000);
	String Url = driver.getCurrentUrl();
	System.out.println(Url);
	if (Url.equals("https://www.amazon.es/")){
	System.out.println("Amazon current URL - Passed");
	}
	else {
	System.out.println("Amazon current URL - Failed");
	}
	// Navigate to gmail web page
	driver.navigate().to("www.gmail.com");
	Thread.sleep(5000);
	String GmailTitle = driver.getTitle();
	System.out.println(GmailTitle);
	if (GmailTitle.equals("Gmail: Correo electrónico y almacenamiento gratuito de Google")){
		System.out.println("The Gmail web page tittle - Passed");
	}
	else {
			System.out.println("The Gmail web page tittle - Failed");
		}
	// Return to Amazon Main Page
	driver.navigate().back();
	Thread.sleep(5000);
	Assert.assertEquals(driver.findElement(By.id("nav-your-amazon")).getText(), "Mi Amazon.es");
	// Close IExplorer and Quit WebDriver
	driver.close();
	driver.quit();
	}
}

3.- Third class name: ThirdClassTestNg. It contains the following tests:

  • Launch Chrome browser.
  • Data driven test from external DataInput.txt file.
  • Data input login and password failed from external file .txt.
  • Verify the url and count the iteration. Verify the error and return message passed/failed.
public class ThirdClassTestNg {
	public static WebDriver driver;// driver declaration for run browser in all methods
	public static String line;
	public static int Iteration;

	// Data Driven test from DataInput.txt file for login and password
	@Test
	public void DataDrivenLogin() throws IOException, InterruptedException {
		FileReader file = new FileReader("C:/SeleniumDoc/FirsTestNgProject/bin/TestNgPackage/DataInput.txt");
		BufferedReader br = new BufferedReader(file); 

		int count =0;
		Iteration =0;
		while ((line = br.readLine()) != null){
		count = count +1;
		if (count > 1) {
		Iteration = Iteration + 1;
		String [] InputData = line.split(", ", 2);//Read the two columns from DataInput.txt file

		System.setProperty("webdriver.chrome.driver", "C:/SeleniumDoc/chromedriver_win32/chromedriver.exe");
		driver = new ChromeDriver();
		driver.manage().window().maximize();
		driver.get("https://www.amazon.es");
		Thread.sleep(5000);
		driver.findElement(By.id("nav-link-yourAccount")).click();
		driver.findElement(By.id("ap_email")).sendKeys(InputData[0]);
		driver.findElement(By.id("ap_password")).sendKeys(InputData[1]);
		driver.findElement(By.id("signInSubmit")).click();
		Thread.sleep(5000);

		String url = driver.getCurrentUrl();

		// Login user and password failed
		if (url.equals("https://www.amazon.es/ap/signin")){
		Assert.assertEquals(driver.findElement(By.className("a-spacing-small")).getText(), "Iniciar sesión");
		System.out.println("Iteration-"+Iteration+ " - Login Unsuccessful - Failed");
		}
		else {
		System.out.println("Iteration-"+Iteration+ " - Login Successful - Passed");
		}
		driver.close();
		}
		}
		file.close();
		br.close();
  }
}

4.- The main point for execute all TestNG classes is the XML file. Generate XML TestNG for run project. The name is: “testng.xml”

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE suite SYSTEM “http://testng.org/testng-1.0.dtd”&gt;
<suite name=”Suite”>
<test name=”Test”>
<classes>
<class name=”TestNgPackage.FirstClassTestNg”>
<methods>
<include name=”LaunchAmazonMain” />
<include name=”testAmazonMainPage” />
<include name=”verifyLinkText” />
<include name=”verifyReturnHome” />
</methods>
</class>
<class name=”TestNgPackage.SecondClassTestNgIe”>
<methods>
<include name=”LaunchAmazonMain” />
</methods>
</class>
<class name=”TestNgPackage.ThirdClassTestNg”>
<methods>
<include name=”DataDrivenLogin” />
</methods>
</class>
</classes>
</test> <!– Test –>
</suite> <!– Suite –>

5.- Download Jenkins (Continuous Integration) and run xml file periodically every day.

  • Download Jenkins (jenkins.war file) https://jenkins.io/download/
  • Open jenkins.war execute in CMD> Project_home_Directory> java -jar Jenkins.war
  • Ex…       cd C:\SeleniumDoc\FirsTestNgProject
  •                 C:\SeleniumDoc\FirsTestNgProject> java -jar Jenkins.war 
  • Go to browser> localhost:8080 > Manage Jenkins:
  • > System configuration > main jenkins directory -> C:\Users\<userName>\.jenkins -> email: your mail address.
  • > Manage Jenkins > JDK Installations -> JDK NAME: JAVA_HOME -> C:\Program Files\Java\jdk1.8.0_73 -> Apply and Save.

jenkins-1

  • Create a New Task > Name: SeleniumFirstProject >  Build a free-style software project > OK
  • > Navigate to Advanced Project Options > Use custom workspace -> C:\SeleniumDoc\FirsTestNgProject
  • Create .bat file execution > new .txt file, including: java -cp bin;C:\SeleniumDoc\Seleniumtests\JAR\selenium-java-2.47.1\selenium-2.47.1\libs/* org.testng.TestNG testng.xml
  • And save with the name “run.bat” on folder C:\SeleniumDoc\FirsTestNgProject.

jenkins-8-_packageexplorer

  • Execute Windows batch command -> run.bat

jenkins-2

  • Apply and Save.
  • Build Now. -> Results are shown in Console output.

jenkins-4

jenkins-5

jenkins-6.png

6.- Add a nice TestNG report results with TestNG Results plugin to Jenkins.

  • Download “TestNG Results plugin” for xml file on Jenkins manage plugins.
  • Mofify the configuration of “FirstTestNgproject” Jenkins project.
  • Add new action after execution in the project.
  • Select “Publish TestNG Results” > TestNG XML report pattern = **/testng-results.xml > Apply and Save.
  • Build now.
  • After build appears “TestNG Results” link > you can see the details of results on table. Also, you can see the methods results.

jenkins-9

jenkins-10

7.- Schedule your build in Jenkins for periodic execution:

  • Jenkins will accept 5 parameter lets discuss one by one. For our example is:
  • 01 * * * * -> means every hour + 1 minut. Ex. 08:01, 09:01, 10:01…
  • * * * * *
  • Here the first parameter- specify minute and range will vary from 0-59
  • Here the second parameter- specify hours and range will vary from 0-11
  • Here the third parameter- specify day and range will vary from 0-7 here 0 and 7 will be Sunday
  • Here the fourth parameter- specify month and range will vary from 1-12
  • Here the fifth parameter- specify year so here you can specify *
  • Example 1- if you specify    00 22 * * *  it means your build will run daily @ 10 PM
  • Example 2- if you specify    50 * * * *  it means your build will run daily  50 min  after every hour
  • Example 3- if you specify    00 22 1 * *  it means your build will run every Monday @ 10 PM

jenkins-7

8.- References: