Successfully reported this slideshow.
Your SlideShare is downloading. ×

QA Fest 2019. Saar Rachamim. Developing Tools, While Testing

Ad

Develop Tools, While Testing
Saar Rachamim, Gett

Ad

About Me
Saar Rachamim
BE Developer @Gett
saarr@gett.com

Ad

About Me
Developing automation tools
Innovation

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Loading in …3
×

Check these out next

1 of 67 Ad
1 of 67 Ad

QA Fest 2019. Saar Rachamim. Developing Tools, While Testing

Our daily work is comprised of testing a product and improve its quality. However, here and there, we can come to a state where we find a need to build a tool, that can make our work easierbetter.
I will share from my experience when I found myself in a situation where building a tool was needed.
We will start with a web application that allows you to know when a food delivery you ordered arrives to the office, and then we will focus on a tool that test the performance of an app from the UI side. We will do a live demo for both of them.

Our daily work is comprised of testing a product and improve its quality. However, here and there, we can come to a state where we find a need to build a tool, that can make our work easierbetter.
I will share from my experience when I found myself in a situation where building a tool was needed.
We will start with a web application that allows you to know when a food delivery you ordered arrives to the office, and then we will focus on a tool that test the performance of an app from the UI side. We will do a live demo for both of them.

More Related Content

More from QAFest

QA Fest 2019. Saar Rachamim. Developing Tools, While Testing

  1. 1. Develop Tools, While Testing Saar Rachamim, Gett
  2. 2. About Me Saar Rachamim BE Developer @Gett saarr@gett.com
  3. 3. About Me Developing automation tools Innovation
  4. 4. About Me Developing automation tools Innovation
  5. 5. Automate everything def main(): time.sleep(17) conn = telnetlib.Telnet(host=COFFEE_MACHINE_ADDR) conn.open() conn.expect([COFFEE_MACHINE_PROM]) conn.write(COFFEE_MACHINE_PASS) conn.write('sys brew') time.sleep(64) conn.write('sys pour') conn.close()
  6. 6. Automate everything def main(): time.sleep(17) conn = telnetlib.Telnet(host=COFFEE_MACHINE_ADDR) conn.open() conn.expect([COFFEE_MACHINE_PROM]) conn.write(COFFEE_MACHINE_PASS) conn.write('sys brew') time.sleep(64) conn.write('sys pour') conn.close()
  7. 7. Automate everything
  8. 8. Origin Story
  9. 9. Origin Story 23 22 21
  10. 10. Origin Story
  11. 11. Origin Story
  12. 12. Origin Story
  13. 13. Origin Story
  14. 14. Origin Story
  15. 15. Origin Story
  16. 16. Origin Story
  17. 17. Origin Story
  18. 18. Origin Story
  19. 19. Origin Story
  20. 20. Design . . .
  21. 21. Design
  22. 22. Demo
  23. 23. Gett’s Road A product loved for its quality Join the ride
  24. 24. Automation Performance Tool Origin Story
  25. 25. App Stability Problem
  26. 26. App Stability
  27. 27. Solutions
  28. 28. Solutions Manual Automation
  29. 29. Solutions Manual Automation Third party In-house
  30. 30. Selected Solution: Developing in House Tool
  31. 31. Developing your own tool ● Questions in mind ○ What language to choose (JavaC#...)
  32. 32. Developing your own tool ● Questions in mind ○ What language to choose (JavaC#...) ○ What platform - mobile, desktop or web
  33. 33. Developing your own tool ● Questions in mind ○ What language to choose (JavaC#...) ○ What platform - mobile, desktop or web ○ DB: Sql, NoSql
  34. 34. Design
  35. 35. Design
  36. 36. Design
  37. 37. Design
  38. 38. Design
  39. 39. The Tool Code
  40. 40. Test Code public class SeleniumTest { @Test public void test(){ String testName = Thread.currentThread().getStackTrace()[1].getMethodName(); new ThreadExecuter(testName).execute(); new TestExecuter().execute(); } }
  41. 41. Test Code public class SeleniumTest { @Test public void test(){ String testName = Thread.currentThread().getStackTrace()[1].getMethodName(); new ThreadExecuter(testName).execute(); new TestExecuter().execute(); } }
  42. 42. Test Code public class SeleniumTest { @Test public void test(){ String testName = Thread.currentThread().getStackTrace()[1].getMethodName(); new ThreadExecuter(testName).execute(); new TestExecuter().execute(); } }
  43. 43. Test Code public class SeleniumTest { @Test public void test(){ String testName = Thread.currentThread().getStackTrace()[1].getMethodName(); new ThreadExecuter(testName).execute(); new TestExecuter().execute(); } }
  44. 44. Test Code public class TestExecuter { public void execute(){ WebDriver driver = new ChromeDriver(); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); boolean stop = false; while(stop){ try{ driver.get(Constants.GOOGLE); WebElement searchField = driver.findElement(By.xpath(Constants.SEARCH_FIELD)); searchField.sendKeys(new TextGenerator().getTextToSearch()); WebElement searchButton = driver.findElement(By.xpath(Constants.SEARCH_BUTTON)); searchButton.click(); Thread.sleep(Constants.FIVE_SECONDS); } catch(Exception e){} } } }
  45. 45. Test Code public class TestExecuter { public void execute(){ WebDriver driver = new ChromeDriver(); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); boolean stop = false; while(stop){ try{ driver.get(Constants.GOOGLE); WebElement searchField = driver.findElement(By.xpath(Constants.SEARCH_FIELD)); searchField.sendKeys(new TextGenerator().getTextToSearch()); WebElement searchButton = driver.findElement(By.xpath(Constants.SEARCH_BUTTON)); searchButton.click(); Thread.sleep(Constants.FIVE_SECONDS); } catch(Exception e){} } } }
  46. 46. Process Handler Code public String getCpuUsageByProcessName(String name) throws IOException { String[] inputArr = {"ps", "-em", "-o", "%cpu,command"}; String retVal = executeTerminalCommands(inputArr, name); return returnSubStringAccordingStr(retVal, " /").replace(" ", ""); } private String executeTerminalCommands(String[] inputArr, String commandPart) throws IOException { String line; Process process = Runtime.getRuntime().exec(inputArr); BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream())); while ((line = input.readLine()) != null) { if (line.contains(commandPart)) { return line; } } return "-1"; }
  47. 47. Process Handler Code public String getCpuUsageByProcessName(String name) throws IOException { String[] inputArr = {"ps", "-em", "-o", "%cpu,command"}; String retVal = executeTerminalCommands(inputArr, name); return returnSubStringAccordingStr(retVal, " /").replace(" ", ""); } private String executeTerminalCommands(String[] inputArr, String commandPart) throws IOException { String line; Process process = Runtime.getRuntime().exec(inputArr); BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream())); while ((line = input.readLine()) != null) { if (line.contains(commandPart)) { return line; } } return "-1"; }
  48. 48. Process Handler Code public String getCpuUsageByProcessName(String name) throws IOException { String[] inputArr = {"ps", "-em", "-o", "%cpu,command"}; String retVal = executeTerminalCommands(inputArr, name); return returnSubStringAccordingStr(retVal, " /").replace(" ", ""); } private String executeTerminalCommands(String[] inputArr, String commandPart) throws IOException { String line; Process process = Runtime.getRuntime().exec(inputArr); BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream())); while ((line = input.readLine()) != null) { if (line.contains(commandPart)) { return line; } } return "-1"; }
  49. 49. Process Handler Code public String getCpuUsageByProcessName(String name) throws IOException { String[] inputArr = {"ps", "-em", "-o", "%cpu,command"}; String retVal = executeTerminalCommands(inputArr, name); return returnSubStringAccordingStr(retVal, " /").replace(" ", ""); } private String executeTerminalCommands(String[] inputArr, String commandPart) throws IOException { String line; Process process = Runtime.getRuntime().exec(inputArr); BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream())); while ((line = input.readLine()) != null) { if (line.contains(commandPart)) { return line; } } return "-1"; }
  50. 50. Requests Handler Code ProcessHandler ph = new ProcessHandler(); RequestHandler requestHandler = new RequestHandler(Constants.FB_URL); String retKey = requestHandler.postHttp("", new String[]{"Content-Type", "Authorization"}, new String[]{"application/x- www-form-urlencoded", "key=" + Constants.SECRET}, "{"time":"" + Calendar.getInstance().getTime() + "", "testName":"" + testName + "", "browser":"Chrome"}"); while (true) { try { String cpu = ph.getCpuUsageByProcessName(Constants.PROCESS_NAME); String mem = ph.getMemoryUsageByProcessName(Constants.PROCESS_NAME); requestHandler.postHttp(retKey, new String[]{"Content-Type", "Authorization"}, new String[]{"application/x- www-form-urlencoded", "key=" + Constants.SECRET}, "{"mem":"" + mem + "","cpu":"" + cpu + "", "time":"" + Calendar.getInstance().getTime() + ""}"); } catch (Exception e) { System.out.println(e); } }
  51. 51. Requests Handler Code ProcessHandler ph = new ProcessHandler(); RequestHandler requestHandler = new RequestHandler(Constants.FB_URL); String retKey = requestHandler.postHttp("", new String[]{"Content-Type", "Authorization"}, new String[]{"application/x- www-form-urlencoded", "key=" + Constants.SECRET}, "{"time":"" + Calendar.getInstance().getTime() + "", "testName":"" + testName + "", "browser":"Chrome"}"); while (true) { try { String cpu = ph.getCpuUsageByProcessName(Constants.PROCESS_NAME); String mem = ph.getMemoryUsageByProcessName(Constants.PROCESS_NAME); requestHandler.postHttp(retKey, new String[]{"Content-Type", "Authorization"}, new String[]{"application/x- www-form-urlencoded", "key=" + Constants.SECRET}, "{"mem":"" + mem + "","cpu":"" + cpu + "", "time":"" + Calendar.getInstance().getTime() + ""}"); } catch (Exception e) { System.out.println(e); } }
  52. 52. Requests Handler Code ProcessHandler ph = new ProcessHandler(); RequestHandler requestHandler = new RequestHandler(Constants.FB_URL); String retKey = requestHandler.postHttp("", new String[]{"Content-Type", "Authorization"}, new String[]{"application/x- www-form-urlencoded", "key=" + Constants.SECRET}, "{"time":"" + Calendar.getInstance().getTime() + "", "testName":"" + testName + "", "browser":"Chrome"}"); while (true) { try { String cpu = ph.getCpuUsageByProcessName(Constants.PROCESS_NAME); String mem = ph.getMemoryUsageByProcessName(Constants.PROCESS_NAME); requestHandler.postHttp(retKey, new String[]{"Content-Type", "Authorization"}, new String[]{"application/x- www-form-urlencoded", "key=" + Constants.SECRET}, "{"mem":"" + mem + "","cpu":"" + cpu + "", "time":"" + Calendar.getInstance().getTime() + ""}"); } catch (Exception e) { System.out.println(e); } }
  53. 53. Html Code <div class="container"> <div class="jumbotron"> <div class="panel-heading"></div> <div ng-controller="MyController"> <div class="text-center"> <select ng-options="testName as testName for testName in testsNames" ng-model="selectedTest"></select> <select ng-options="testTime as testTime for testTime in testsTime" ng-model="timeSelected"></select> <select ng-options="measurement as measurement for measurement in measurements" ng- model="measurementSelected"></select> <button type="button" class="btn btn-primary my-2" ng-click="createGraph(selectedTest, timeSelected, measurementSelected)">Execute</button> </div> <div class="text-left" style="margin-top:30px">
  54. 54. Html Code <div class="container"> <div class="jumbotron"> <div class="panel-heading"></div> <div ng-controller="MyController"> <div class="text-center"> <select ng-options="testName as testName for testName in testsNames" ng-model="selectedTest"></select> <select ng-options="testTime as testTime for testTime in testsTime" ng-model="timeSelected"></select> <select ng-options="measurement as measurement for measurement in measurements" ng- model="measurementSelected"></select> <button type="button" class="btn btn-primary my-2" ng-click="createGraph(selectedTest, timeSelected, measurementSelected)">Execute</button> </div> <div class="text-left" style="margin-top:30px">
  55. 55. Angular Code $scope.createGraph = function (selectedTest, timeSelected, measurementSelected) { ... angular.forEach(array, function (test) { if (test.time == timeSelected && test.testName == selectedTest) { $scope.currentData = new Array(); for (var key in test) { var specimentRecord = test[key]; if (specimentRecord != null && typeof specimentRecord !== "undefined") { $scope.currentData.push(specimentRecord); $scope.currentlabels.push(specimentRecord.time); } } $scope.currentData = $filter('orderBy')($scope.currentData, "time"); $scope.data = new Array(); $scope.labels = new Array(); for (var key in $scope.currentData) { if (measurementSelected == "cpu" && typeof $scope.currentData[key].cpu !== "undefined") $scope.data.push($scope.currentData[key].cpu); if (measurementSelected == "memory" && typeof $scope.currentData[key].mem !== "undefined") $scope.data.push($scope.currentData[key].mem); if (typeof $scope.currentData[key].cpu !== "undefined" || typeof $scope.currentData[key].mem !== "undefined") $scope.labels.push($scope.currentData[key].time); }
  56. 56. Angular Code $scope.createGraph = function (selectedTest, timeSelected, measurementSelected) { ... angular.forEach(array, function (test) { if (test.time == timeSelected && test.testName == selectedTest) { $scope.currentData = new Array(); for (var key in test) { var specimentRecord = test[key]; if (specimentRecord != null && typeof specimentRecord !== "undefined") { $scope.currentData.push(specimentRecord); $scope.currentlabels.push(specimentRecord.time); } } $scope.currentData = $filter('orderBy')($scope.currentData, "time"); $scope.data = new Array(); $scope.labels = new Array(); for (var key in $scope.currentData) { if (measurementSelected == "cpu" && typeof $scope.currentData[key].cpu !== "undefined") $scope.data.push($scope.currentData[key].cpu); if (measurementSelected == "memory" && typeof $scope.currentData[key].mem !== "undefined") $scope.data.push($scope.currentData[key].mem); if (typeof $scope.currentData[key].cpu !== "undefined" || typeof $scope.currentData[key].mem !== "undefined") $scope.labels.push($scope.currentData[key].time); }
  57. 57. Angular Code $scope.createGraph = function (selectedTest, timeSelected, measurementSelected) { ... angular.forEach(array, function (test) { if (test.time == timeSelected && test.testName == selectedTest) { $scope.currentData = new Array(); for (var key in test) { var specimentRecord = test[key]; if (specimentRecord != null && typeof specimentRecord !== "undefined") { $scope.currentData.push(specimentRecord); $scope.currentlabels.push(specimentRecord.time); } } $scope.currentData = $filter('orderBy')($scope.currentData, "time"); $scope.data = new Array(); $scope.labels = new Array(); for (var key in $scope.currentData) { if (measurementSelected == "cpu" && typeof $scope.currentData[key].cpu !== "undefined") $scope.data.push($scope.currentData[key].cpu); if (measurementSelected == "memory" && typeof $scope.currentData[key].mem !== "undefined") $scope.data.push($scope.currentData[key].mem); if (typeof $scope.currentData[key].cpu !== "undefined" || typeof $scope.currentData[key].mem !== "undefined") $scope.labels.push($scope.currentData[key].time); }
  58. 58. Angular Code $scope.createGraph = function (selectedTest, timeSelected, measurementSelected) { ... angular.forEach(array, function (test) { if (test.time == timeSelected && test.testName == selectedTest) { $scope.currentData = new Array(); for (var key in test) { var specimentRecord = test[key]; if (specimentRecord != null && typeof specimentRecord !== "undefined") { $scope.currentData.push(specimentRecord); $scope.currentlabels.push(specimentRecord.time); } } $scope.currentData = $filter('orderBy')($scope.currentData, "time"); $scope.data = new Array(); $scope.labels = new Array(); for (var key in $scope.currentData) { if (measurementSelected == "cpu" && typeof $scope.currentData[key].cpu !== "undefined") $scope.data.push($scope.currentData[key].cpu); if (measurementSelected == "memory" && typeof $scope.currentData[key].mem !== "undefined") $scope.data.push($scope.currentData[key].mem); if (typeof $scope.currentData[key].cpu !== "undefined" || typeof $scope.currentData[key].mem !== "undefined") $scope.labels.push($scope.currentData[key].time); }
  59. 59. Angular Code $scope.createGraph = function (selectedTest, timeSelected, measurementSelected) { ... angular.forEach(array, function (test) { if (test.time == timeSelected && test.testName == selectedTest) { $scope.currentData = new Array(); for (var key in test) { var specimentRecord = test[key]; if (specimentRecord != null && typeof specimentRecord !== "undefined") { $scope.currentData.push(specimentRecord); $scope.currentlabels.push(specimentRecord.time); } } $scope.currentData = $filter('orderBy')($scope.currentData, "time"); $scope.data = new Array(); $scope.labels = new Array(); for (var key in $scope.currentData) { if (measurementSelected == "cpu" && typeof $scope.currentData[key].cpu !== "undefined") $scope.data.push($scope.currentData[key].cpu); if (measurementSelected == "memory" && typeof $scope.currentData[key].mem !== "undefined") $scope.data.push($scope.currentData[key].mem); if (typeof $scope.currentData[key].cpu !== "undefined" || typeof $scope.currentData[key].mem !== "undefined") $scope.labels.push($scope.currentData[key].time); }
  60. 60. Angular Code $scope.createGraph = function (selectedTest, timeSelected, measurementSelected) { ... angular.forEach(array, function (test) { if (test.time == timeSelected && test.testName == selectedTest) { $scope.currentData = new Array(); for (var key in test) { var specimentRecord = test[key]; if (specimentRecord != null && typeof specimentRecord !== "undefined") { $scope.currentData.push(specimentRecord); $scope.currentlabels.push(specimentRecord.time); } } $scope.currentData = $filter('orderBy')($scope.currentData, "time"); $scope.data = new Array(); $scope.labels = new Array(); for (var key in $scope.currentData) { if (measurementSelected == "cpu" && typeof $scope.currentData[key].cpu !== "undefined") $scope.data.push($scope.currentData[key].cpu); if (measurementSelected == "memory" && typeof $scope.currentData[key].mem !== "undefined") $scope.data.push($scope.currentData[key].mem); if (typeof $scope.currentData[key].cpu !== "undefined" || typeof $scope.currentData[key].mem !== "undefined") $scope.labels.push($scope.currentData[key].time); }
  61. 61. Angular Code $scope.createGraph = function (selectedTest, timeSelected, measurementSelected) { ... angular.forEach(array, function (test) { if (test.time == timeSelected && test.testName == selectedTest) { $scope.currentData = new Array(); for (var key in test) { var specimentRecord = test[key]; if (specimentRecord != null && typeof specimentRecord !== "undefined") { $scope.currentData.push(specimentRecord); $scope.currentlabels.push(specimentRecord.time); } } $scope.currentData = $filter('orderBy')($scope.currentData, "time"); $scope.data = new Array(); $scope.labels = new Array(); for (var key in $scope.currentData) { if (measurementSelected == "cpu" && typeof $scope.currentData[key].cpu !== "undefined") $scope.data.push($scope.currentData[key].cpu); if (measurementSelected == "memory" && typeof $scope.currentData[key].mem !== "undefined") $scope.data.push($scope.currentData[key].mem); if (typeof $scope.currentData[key].cpu !== "undefined" || typeof $scope.currentData[key].mem !== "undefined") $scope.labels.push($scope.currentData[key].time); }
  62. 62. Angular Code $scope.createGraph = function (selectedTest, timeSelected, measurementSelected) { ... angular.forEach(array, function (test) { if (test.time == timeSelected && test.testName == selectedTest) { $scope.currentData = new Array(); for (var key in test) { var specimentRecord = test[key]; if (specimentRecord != null && typeof specimentRecord !== "undefined") { $scope.currentData.push(specimentRecord); $scope.currentlabels.push(specimentRecord.time); } } $scope.currentData = $filter('orderBy')($scope.currentData, "time"); $scope.data = new Array(); $scope.labels = new Array(); for (var key in $scope.currentData) { if (measurementSelected == "cpu" && typeof $scope.currentData[key].cpu !== "undefined") $scope.data.push($scope.currentData[key].cpu); if (measurementSelected == "memory" && typeof $scope.currentData[key].mem !== "undefined") $scope.data.push($scope.currentData[key].mem); if (typeof $scope.currentData[key].cpu !== "undefined" || typeof $scope.currentData[key].mem !== "undefined") $scope.labels.push($scope.currentData[key].time); }
  63. 63. Demo
  64. 64. Code Repository https://github.com/saarRachamim/dev/tree/master/ConferenceTests https://github.com/saarRachamim/dev/tree/master/conference_tool
  65. 65. Summary
  66. 66. Contact Information saarrac@gmail.com https://www.linkedin.com/in/saar-rachamim-14055a27/
  67. 67. Questions?

Editor's Notes

  • Add logo of the conference and also on the last slide
  • Add label of the development language
  • Add label of the development language
  • Now will see how it all comes together
  • This is a humeristic image shows a failure of an app.
    There is a message of an SSL error that occured in the app,
    While the comment describe the shakespeare quote to be a head of his time
  • There are third party tools such as: JMeter, WebLoad etc.
    Pros:
    Saves the time needed for development
    In cases that it is a paid tool, then most times it includes support.
    Cons:
    It won’t give us necessarily everything we need.
    Limitations support of programming languages\OS\etc.


  • In house developed tools:
    Pros:
    Adjusted directly to the needs comes from the product.
    Self development.
    Cons:
    Can take a lot of men hours to develop.
    Maintenance time.
  • Make the font bigger
  • To add another slide that shows on what parts of the code we will go through
  • Add label of the development
    This is the code the manages the tests layer
    To try to do it clearer, animations that show parts of the code and not everything in bulk to add explanation about each line that
  • We take the test name, we will show later where it is used
  • We have a thread that manages sending the values of the process that we measure
  • We have another executer for the tests that test the product
  • This is the code of the test that work on the UI, in this case we are testing over Chrome browser
  • In the test we navigate to google site and then searching for different values over the search engine.
    This is just an example for a test, since we are not testing a specific product
  • This is the code for getting the cpu from the a given process,
    We have a very similar code for abstracting the values of the memory of different processes
  • We can see that we get the value using a method called executeTerminalCommands
    We will use the smae function for getting the memory,
    Since the code is used over mac os, different commands will be needed for different os
  • Here we get the process that we want to measure
  • And we are looking for the line that holds the value of the cpu of the specific process that we are measuring.
    This is the returned value for us
  • This code actually sends the the values of the cpu and the memory that we got - to the database.
    The data base can be an in house database or a third party database. As before, this is part of the things we consider
  • Cpu and memory values are obtained
  • And then sent to the db server that handle the data and insert it to the database
  • In the html code , we have a button that trigger a createGraph function
  • This is an angular code with a create graph function
  • We are searching in all the data for the data the was executed in a specific time
  • Each specimentRecord at the test has its own key, so we are going over each key
    Then we are taking each speciment according to the key.

    we are simply taking all the values of the memory and cpu, that we sent during the test
  • We are ordering it according to the time
  • Then we are pusing the data

    cpu
  • memory
  • And the time is also pushed
  • Now will see how it all comes together
  • Split the Slide into 2 parts: contacts and links to github. To put it where it is relevant (showing the code)
  • Split the Slide into 2 parts: contacts and links to github. To put it where it is relevant (showing the code)

×