Automated integration tests for AJAX applications Overview DEVELOPER GARAGE 2012 April 17, Nizhny Novgorod
Justification  Who is part of development team? Who is using …  automated integration (functional) testing  unit-testing  manual testing … to track quality?  Why or how? 2
Agenda •Motivation •Challenges •Solutions & tricks •Experience •Conclusion 3
Motivation – goals •Reliability of the product at any moment •Less time for bugs – more time for development •Feel free to add new features – it’s safe 4
Motivation – issues •Manual testing is slow •Hard to determine guilty commit 5
Reliability at any moment Worst case is: The goal is: 6
Automated tests for AJAX web-applications 7
Challenges - I •Recent framework compared to unit testing •Full-featured container required •New approach (API) •Lack of tools •Relatively faster, but …. relatively slow 8
Challenges - II •Asynchronous behavior •Tricky to configure Hudson/Jenkins •Complicated staging environment configuration •Lack of experienced QA engineers 9
Solutions Challenges • Recent framework compared to unit testing • Tricky to configure Hudson/Jenkins • Lack of experienced QA engineers Solution • Well… Everything happens for the first time • Research, study and teach 10
Solutions Challenges • Complicated staging environment configuration Solution • Test driven application architecture – planning in advance is a key • Use IoC based approach for applications 11
Solutions Challenge •Requires full-featured container •Requires new approach (API) Solution •Use Selenium, jWebUnit 12
Solutions Challenge  Tools… Just few of them Solution  jWebUnit −In case of simple ajax −Turn off javascript if not needed (save 30 seconds)  Selenium −Need to control items visibility −Need to test against real browser 13
Solutions Challenge • Relatively faster, but… relatively slow Solution • Still much faster than manual tests • Define AllInOne suite for quick check • Run full set of tests on CI • Use distributed technologies (i.e. Selenium Grid) 14
Solutions Challenge • Hard to determine guilty commit • Intend to add new features safely Solution • Test all before commit - or at least - • Email notification from CI that commit produced regression 15
Solutions Challenge •Asynchronous behavior Solution •Use wait() approach •Use Thread.sleep() after each action •Be aware of DOM inconsistency 16
Experience Our experience with AJAX apps testing: •GWT application (100% AJAX) •GWTTestCase is not recommended for functional testing •Regular WEB 2.0 application 17
The architecture Server-side running in test environment AJAX Test Cases HTML + JavaScript container Test Cases Test Case running client-side jUnit-style tests Selenium, jWebUnit 18
Source code example (jWebUnit) – 1/3 public class TestShoppingCart extends BaseTest { @Test public void test() { beginAt("/cart/index"); tester.assertTextPresent("Your cart is empty."); tester.setScriptingEnabled(true); beginAt("/album/list?sort=albumName&max=20"); tester.assertElementPresentByXPath("//div[@class='list']"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='0 items']"); tester.clickElementByXPath("//div[@class='album- buy']/input[contains(@value,'Buy Album')]"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='1 item']"); tester.clickElementByXPath("//div[@id='cart']//a"); tester.assertElementPresentByXPath("//div[@id='ribbon-single- line']/h1[contains(., 'Shopping Cart')]"); 19
Source code example (jWebUnit) – 2/3 public class TestShoppingCart extends BaseTest { @Test public void test() { beginAt("/cart/index"); tester.assertTextPresent("Your cart is empty."); tester.setScriptingEnabled(true); beginAt("/album/list?sort=albumName&max=20"); tester.assertElementPresentByXPath("//div[@class='list']"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='0 items']"); tester.clickElementByXPath("//div[@class='album- buy']/input[contains(@value,'Buy Album')]"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='1 item']"); tester.clickElementByXPath("//div[@id='cart']//a"); tester.assertElementPresentByXPath("//div[@id='ribbon-single- line']/h1[contains(., 'Shopping Cart')]"); 20
Source code example (jWebUnit) – 3/3 public class TestShoppingCart extends BaseTest { @Test public void test() { beginAt("/cart/index"); tester.assertTextPresent("Your cart is empty."); tester.setScriptingEnabled(true); beginAt("/album/list?sort=albumName&max=20"); tester.assertElementPresentByXPath("//div[@class='list']"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='0 items']"); tester.clickElementByXPath("//div[@class='album- buy']/input[contains(@value,'Buy Album')]"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='1 item']"); tester.clickElementByXPath("//div[@id='cart']//a"); tester.assertElementPresentByXPath("//div[@id='ribbon-single- line']/h1[contains(., 'Shopping Cart')]"); 21
Source code example (Selenium) – 1/2 public class TestManageChart extends CatalogMerchTestBase { @Test public void testManageChart() throws Throwable { driver.get(baseUrl + "#top.store[1].manage_charts"); waitV("btn-add-chart”); WebElement elm = driver.findElement(By.id("btn-add-chart")); click(elm); Alert alert = getAlert(); alert.sendKeys(newChartName); alert.dismiss(); waitInvAjax(); 22
Source code example (Selenium) – 2/2 public class TestManageChart extends CatalogMerchTestBase { @Test public void testManageChart() throws Throwable { driver.get(baseUrl + "#top.store[1].manage_charts"); waitV("btn-add-chart"); WebElement elm = driver.findElement(By.id("btn-add-chart")); click(elm); Alert alert = getAlert(); alert.sendKeys(newChartName); alert.dismiss(); waitInvAjax(); 23
Experience Time spent. Grouped by task type 25 20 15 10 Before 5 After 0 24
Conclusion & Questions It’s functional testing It’s worth it! Note: Write code with low TCO! Perform code review! Don’t let user story overstep the sprint! 25
Auriga At a Glance  World leader in R&D outsourcing - #1 Engineering Services Outsourcing (ESO) provider - #15 in Top-20 Global Outsourcing Vendors - Global Services 100 and Global Outsourcing 100 company - Top 10 Offshore Eastern and Central Europe - Top 10 Software R&D Service Providers  In business since 1990 - First in Russia to do offshore software services  300 employees  Headquartered in the U.S. - Incorporated in the U.S. in 1993  Engineering centers in - Russia: Moscow, Nizhny Novgorod, Rostov-on-Don - EU: Vilnius, Lithuania  Main Domains: Technologies and Verticals - System Level, Embedded - Technology (s/w and h/w) - Mobile - Finance - Document Management - Healthcare - Portals - Telecom - Social Web - Logistics - Media and Web - Government - Security 26
Contacts Thank You! Sergey.Karpushin@auriga.com 27

Automated integration tests for ajax applications (с. карпушин, auriga)

  • 1.
    Automated integration testsfor AJAX applications Overview DEVELOPER GARAGE 2012 April 17, Nizhny Novgorod
  • 2.
    Justification  Who ispart of development team? Who is using …  automated integration (functional) testing  unit-testing  manual testing … to track quality?  Why or how? 2
  • 3.
  • 4.
    Motivation – goals •Reliabilityof the product at any moment •Less time for bugs – more time for development •Feel free to add new features – it’s safe 4
  • 5.
    Motivation – issues •Manualtesting is slow •Hard to determine guilty commit 5
  • 6.
    Reliability at anymoment Worst case is: The goal is: 6
  • 7.
    Automated tests forAJAX web-applications 7
  • 8.
    Challenges - I •Recentframework compared to unit testing •Full-featured container required •New approach (API) •Lack of tools •Relatively faster, but …. relatively slow 8
  • 9.
    Challenges - II •Asynchronousbehavior •Tricky to configure Hudson/Jenkins •Complicated staging environment configuration •Lack of experienced QA engineers 9
  • 10.
    Solutions Challenges • Recent frameworkcompared to unit testing • Tricky to configure Hudson/Jenkins • Lack of experienced QA engineers Solution • Well… Everything happens for the first time • Research, study and teach 10
  • 11.
    Solutions Challenges • Complicated stagingenvironment configuration Solution • Test driven application architecture – planning in advance is a key • Use IoC based approach for applications 11
  • 12.
    Solutions Challenge •Requires full-featured container •Requiresnew approach (API) Solution •Use Selenium, jWebUnit 12
  • 13.
    Solutions Challenge  Tools… Justfew of them Solution  jWebUnit −In case of simple ajax −Turn off javascript if not needed (save 30 seconds)  Selenium −Need to control items visibility −Need to test against real browser 13
  • 14.
    Solutions Challenge • Relatively faster,but… relatively slow Solution • Still much faster than manual tests • Define AllInOne suite for quick check • Run full set of tests on CI • Use distributed technologies (i.e. Selenium Grid) 14
  • 15.
    Solutions Challenge • Hard todetermine guilty commit • Intend to add new features safely Solution • Test all before commit - or at least - • Email notification from CI that commit produced regression 15
  • 16.
    Solutions Challenge •Asynchronous behavior Solution •Use wait()approach •Use Thread.sleep() after each action •Be aware of DOM inconsistency 16
  • 17.
    Experience Our experience withAJAX apps testing: •GWT application (100% AJAX) •GWTTestCase is not recommended for functional testing •Regular WEB 2.0 application 17
  • 18.
    The architecture Server-side running in test environment AJAX Test Cases HTML + JavaScript container Test Cases Test Case running client-side jUnit-style tests Selenium, jWebUnit 18
  • 19.
    Source code example(jWebUnit) – 1/3 public class TestShoppingCart extends BaseTest { @Test public void test() { beginAt("/cart/index"); tester.assertTextPresent("Your cart is empty."); tester.setScriptingEnabled(true); beginAt("/album/list?sort=albumName&max=20"); tester.assertElementPresentByXPath("//div[@class='list']"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='0 items']"); tester.clickElementByXPath("//div[@class='album- buy']/input[contains(@value,'Buy Album')]"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='1 item']"); tester.clickElementByXPath("//div[@id='cart']//a"); tester.assertElementPresentByXPath("//div[@id='ribbon-single- line']/h1[contains(., 'Shopping Cart')]"); 19
  • 20.
    Source code example(jWebUnit) – 2/3 public class TestShoppingCart extends BaseTest { @Test public void test() { beginAt("/cart/index"); tester.assertTextPresent("Your cart is empty."); tester.setScriptingEnabled(true); beginAt("/album/list?sort=albumName&max=20"); tester.assertElementPresentByXPath("//div[@class='list']"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='0 items']"); tester.clickElementByXPath("//div[@class='album- buy']/input[contains(@value,'Buy Album')]"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='1 item']"); tester.clickElementByXPath("//div[@id='cart']//a"); tester.assertElementPresentByXPath("//div[@id='ribbon-single- line']/h1[contains(., 'Shopping Cart')]"); 20
  • 21.
    Source code example(jWebUnit) – 3/3 public class TestShoppingCart extends BaseTest { @Test public void test() { beginAt("/cart/index"); tester.assertTextPresent("Your cart is empty."); tester.setScriptingEnabled(true); beginAt("/album/list?sort=albumName&max=20"); tester.assertElementPresentByXPath("//div[@class='list']"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='0 items']"); tester.clickElementByXPath("//div[@class='album- buy']/input[contains(@value,'Buy Album')]"); tester.assertElementPresentByXPath("//div[@id=‘c' and .='1 item']"); tester.clickElementByXPath("//div[@id='cart']//a"); tester.assertElementPresentByXPath("//div[@id='ribbon-single- line']/h1[contains(., 'Shopping Cart')]"); 21
  • 22.
    Source code example(Selenium) – 1/2 public class TestManageChart extends CatalogMerchTestBase { @Test public void testManageChart() throws Throwable { driver.get(baseUrl + "#top.store[1].manage_charts"); waitV("btn-add-chart”); WebElement elm = driver.findElement(By.id("btn-add-chart")); click(elm); Alert alert = getAlert(); alert.sendKeys(newChartName); alert.dismiss(); waitInvAjax(); 22
  • 23.
    Source code example(Selenium) – 2/2 public class TestManageChart extends CatalogMerchTestBase { @Test public void testManageChart() throws Throwable { driver.get(baseUrl + "#top.store[1].manage_charts"); waitV("btn-add-chart"); WebElement elm = driver.findElement(By.id("btn-add-chart")); click(elm); Alert alert = getAlert(); alert.sendKeys(newChartName); alert.dismiss(); waitInvAjax(); 23
  • 24.
    Experience Time spent. Groupedby task type 25 20 15 10 Before 5 After 0 24
  • 25.
    Conclusion & Questions It’sfunctional testing It’s worth it! Note: Write code with low TCO! Perform code review! Don’t let user story overstep the sprint! 25
  • 26.
    Auriga At aGlance  World leader in R&D outsourcing - #1 Engineering Services Outsourcing (ESO) provider - #15 in Top-20 Global Outsourcing Vendors - Global Services 100 and Global Outsourcing 100 company - Top 10 Offshore Eastern and Central Europe - Top 10 Software R&D Service Providers  In business since 1990 - First in Russia to do offshore software services  300 employees  Headquartered in the U.S. - Incorporated in the U.S. in 1993  Engineering centers in - Russia: Moscow, Nizhny Novgorod, Rostov-on-Don - EU: Vilnius, Lithuania  Main Domains: Technologies and Verticals - System Level, Embedded - Technology (s/w and h/w) - Mobile - Finance - Document Management - Healthcare - Portals - Telecom - Social Web - Logistics - Media and Web - Government - Security 26
  • 27.
    Contacts Thank You! Sergey.Karpushin@auriga.com 27