Retrospection and learning time

Just recently, my engagement to my project since Nov of last year has ramped down. So the past couple of weeks has been a time of transition for me into my upcoming project and also from me to the new PO of my previous project. This allowed an opportunity for retrospection, and also a chance to pick up on new stuff.

While looking up the available knowledge sharing platforms within the company, I came across the option to host stuff in our enterprise GitHub instance. One link led to another, and I came across…

  • MkDocs – This is for project documentation; it allows the use of Markdown for writing content, and then you generate static site contents from that.
  • Documentation as Code (docs-as-code) – While I’m not a programmer, getting familiar with the concept wouldn’t hurt. And as I read more, it’s not really exclusive to programmers.
  • Diagrams as Code with Mermaid – Part of the family of stuff-as-code, this doesn’t trail far behind. I think what I find promising about this (apart from being free) is that this is going make comparison of versions easier since you’re comparing text files.

As mentioned, I did some retrospection. I collated some of my personal lessons learned and posted it in our project’s Confluence page. I also revisited Software Development’s Classic Mistakes. I tried rereading The Scrum Guide and some stuff on anti-patterns to see where we’re somewhat deviating (for guidance if it’s something we should continue or if we should “realign”). Then I tried to pull out project-agnostic stuff that could be helpful to me for starting a new Agile Scrum project and collated my notes.

With the notes in hand, I’m starting to use it as a reference for the new project, and I plan to just tweak accordingly as I find other useful stuff to add in. At this stage, there’s already a team working on the prototypes, and in theory, they’re prepping the solution or the design which will be handed over to the implementation team. So I’ll be keen on learning a lot more and looking for process improvements for the handover from Design Thinking to prototyping to implementation. Exciting stuff! 🙂

Bug Magnet Chrome Extension

I just remembered that I have this Chrome Extension installed called Bug Magnet. It comes in pretty handy while exploratory testing to try to see if the app breaks when different inputs are entered. It allows you to enter various inputs — could be valid, invalid, with special characters, super long text, etc. So just in case you get asked to very, very quickly try out a new application / website that allows user inputs, then this Chrome Extension could also help refresh your memory for cases/inputs to try out.

20170222-184501-register-supercar-showdown

July 2016 Meetup of Software Testing Philippines

I attended a local software testing meetup yesterday. Typically, I’d only join if the venue was near work, but I had the day off so stressing out over getting to the venue wasn’t an issue. What also lured me in is that there would be a talk on chartered exploratory testing and mind mapping. It’s not the first time I’ve ever heard of those things, but to hear about them in a local context was something that got me interested.

Actually, hearing things in a local context is why I generally bother to attend these meetups. You can google the concepts, you can google for tools, but you can’t google how other peers are doing software testing locally.

So the meetup had 2 parts — 3 if you count the part where we got fed free pizza and soft drinks. There was the talk on Collaborative Test Design by Ian Pestelos (I’ll link to the slides if the deck gets shared), and there was an Open Space discussion. Since “Open Space” was in title-case, I went ahead and googled it and found this (from Martin Fowler’s site) and this (how to run an Open Space event). An interesting take-away from googling about Open Space is The Law of Two Feet:

If, during the course of the gathering, any person finds themselves in a situation where they are neither learning nor contributing, they must go to some more productive place.

Overall, I enjoyed Ian’s talk, and I wouldn’t have second thoughts about recommending it to peers. The Open Space discussion, not my favorite thing. Would I go to one of these meetups again? Sure, if there’d be talks on topics I find interesting and if my schedule permits.

(Just some notes after the read-more)

Continue reading

Trying out Postman

One of the tools that we’ve used in our project is Postman. It’s a Google Chrome App wherein we can send the web service request and then view the response in a prettier, much readable style.

In one of our user stories for this Sprint, we needed to come up with the list of profiles that needs to be deactivated because the employee had become inactive. To verify whether the employee had become inactive, we had to check against an employee database. To check, you can go visit a search site, search for that user, and view the search result. Using their provided API, you can pretty much do the same with Postman. Submit the request with the email passed as parameter and evaluate the result.

01-single-request

But then, sometimes you have to check several employees at a time and it turns out we can use Postman to test in batches. To accomplish that what I did was the following:

1. Whether you run it one at a time or in batches, I defined my tests. Below is the snippets I used in my tests which checks for a 200 status being returned, and for whether the employee status field has value not equal to Active.

tests["Status code is 200"] = responseCode.code === 200;

try {
    var responseJSON = JSON.parse(responseBody);
    tests["Employee is NOT Active"] = "Active" != responseJSON.result[0].empStatus;
}
catch (e) { }

2. I used a variable for the parameter e.g., {{email}}.

02-parameter

3. I saved the parameter values in .csv format where the first line (treated as the header) use the variable used as parameter, in this case “email”.

4. I saved the request (with the tests and params) into a collection.

5. Then I used the Collection Runner to select the collection I want to run, the csv file with the data to pass as parameter values, and to indicate the number of iterations. Results are then displayed at the rightmost panel.

3-collection-runner

So there. I probably haven’t even scratched the surface of how else Postman can be used. But it’s been pretty nifty for this particular use case.

Automated testing with CucumberJS with Selenium Webdriver using JavaScript

I’m currently picking up something new at work. And I guess the title of the post gives it away. It’s not a brand new thing altogether, just something that I haven’t tried out before. And in one of the blogs I stumbled upon, there was a line that captured what I wanted to do in this post (and I guess in a lot of other previous posts too): helping me remember what I figure[d] out. Anyways, this is just a gist of the basic setup. Much of the learning is in the actual scripting, and most of it is when things don’t work as expected.

First things first: Setting up

  • Download and install Node from https://nodejs.org/en/download. This will also install the Node Package Manager (NPM).
  • Download the drivers into a folder in your local.
  • Update your environment variables to include the drivers into your PATH variable.
    • Add SELENIUM_DRIVERS as a system variable and specify the folder where you placed the drivers
    • Update the PATH system variable by appending “;%SELENIUM_DRIVERS%;”
  • We used a starter found here. Download the files from there, and that’ll give us stuff that I have no idea how to write from scratch at this point:
    • package.json
    • Gruntfile.js
    • features/support folder contains world.js, env.js and hooks.js
  • Install the needed dependencies.
    • Dependencies like CucumberJS, Chai, Selenium Webdriver, etc. are indicated in the package.json file.
    • Open the Command Prompt, then go to the folder where the starter files are placed. Run “npm install”.

Writing our Feature File and Step Definitions

Since we’re using CucumberJS, we’ll write up a feature file in Gherkin format. This means that scenarios that we’ll be testing for are written in a Given-When-Then format. Given includes the needed setup for the test. When refer to actions taken from the initial state (as setup in the Givens). And Then includes the expected outcomes that will be checked for.

For each Given, When and Then, corresponding code has to be written to actually perform the automated steps. These steps are stored in step definition files stored under features/step_definitions.

Feature: Searching for cucumbers
  As an internet user
  In order to find out more about cucumbers
  I want to be able to search for information about cucumbers

  Scenario: Google cucumber search
    Given I go to the Google website
    When I search Google for "cucumbers"
    Then I should see some results
'use strict';

var expect = require('chai').expect;

module.exports = function() {
  this.World = require('../support/world.js').World;

  this.Given('I go to the Google website', function (next) {
    this.browser.get('http://www.google.com').then(function () {
      next();
    });
  });

  this.When('I search Google for "$searchQuery"', function (searchQuery, next) {

    this.browser.findElement(this.webdriver.By.css('input[name="q"]')).sendKeys(searchQuery);
    this.browser.findElement(this.webdriver.By.css('input[name="q"]')).sendKeys(this.webdriver.Key.ENTER)
    .then(function () {
      next();
    });
  });

  this.Then('I should see some results', function (next) {
    this.waitFor('div.g', 10000);
    this.browser.findElements(this.webdriver.By.css('div.g')).then(function (elements) {
      expect(elements.length).to.not.equal(0);
      next();
    });
  });
};

Okay, actually writing our step definitions

To interact with the web site under test, we use Selenium Webdriver. While working on a POC, we had to look for elements within the page under test, and then interact with those elements by either triggering an action like clicking or sending keys or we also interact by extracting information about the element I found. For the checks in the Then steps, we use Chai to do the comparisons. For the POC at least, I pretty much managed to get by with simple scenarios using the items below.


//Finding Elements with Selenium Webdriver
//Find Element by ID
this.browser.findElement(this.webdriver.By.id('sp-search-input'))

//Find Element by CSS
this.browser.findElement(this.webdriver.By.css('#sp-search-input'))
this.browser.findElement(this.webdriver.By.css('.ui-chip'))
this.browser.findElement(this.webdriver.By.css('.ui-chip[data-val="hello"]'))

//Interacting with Elements with Selenium Webdriver
this.browser.findElement(this.webdriver.By.id('sp-search-input')).sendKeys(searchText+"\n");
this.browser.findElement(this.webdriver.By.id('sp-add-widget')).click();
this.browser.findElement(this.webdriver.By.css('.ui-chip>span')).getText();
//looks for element with class "ui-chip" and then looks for a <span> and gets the text in that <span>

this.browser.findElement(this.webdriver.By.id('sp-search-input')).getAttribute('placeholder');
//e.g., <input id="sp-search-input" placeholder="Add Search Tags" …>
//above will return "Add Search Tags"

this.browser.isElementPresent(this.webdriver.By.css('.ui-toggle.checked'));
//returns boolean value

//Comparisons using Chai
expect(actualText).to.equal(expectedText);
expect(textFound).to.contain(expectedString);
expect(toggleState).to.be.ok;

Running our scripts

Using the Command Prompt, go to your test project folder, then run “cucumber-js”. There’s also an option to run it with other options. I find the tags to be most helpful. What I do is I tag the scenarios that I’m working on in the feature file. The format of the tag is “@tagname” in the line before the scenario you are tagging.

cucumber-js --tags @dev               //tagged with @dev
cucumber-js --tags ~@dev              //NOT tagged with @dev
cucumber-js --tags @foo,@bar          //tagged with @foo OR bar
cucumber-js --tags @foo --tags @bar   //tagged with @foo AND bar

Well, that’s about it. Again, the learning really comes when you’re actually scripting. Sometimes, you just need to dive in knowing you don’t know everything, and hopefully you’ll figure it out as you go along.

Summary of references

Example, Starter – https://github.com/Matt-B/cucumber-js-selenium-webdriver-example
CSS Selectors – http://www.w3schools.com/cssref/css_selectors.asp
Chai – http://chaijs.com/api/bdd/
Selenium Webdriver – http://www.seleniumhq.org/docs/03_webdriver.jsp
CucumberJS – https://github.com/cucumber/cucumber-js
Gherkin – https://github.com/cucumber/cucumber/wiki/Gherkin
Cucumber – http://cukes.info
Cucumber tags – https://github.com/cucumber/cucumber/wiki/Tags
Blog post – http://www.tcias.co.uk/blog/2014/09/03/writing-our-first-functional-test/ (2014 Sep 3)
Blog post – http://transitioning.to/2012/01/cucumber-and-js-getting-started-with-cucumber-js/ (2012 Jan 27)

Basic QTP Training: Enhancing our script

The past couple of days of our QTP training covered a lot more ground. The most nifty stuff are on tools like the Object Repository, the Object Spy (which is an icon of a guy with a top hat reminding me of Professor Layton), the Active Screen, and the topics on parameterization. I created a short video covering the last 2 topics. So there I demonstrate two things:

  • Updating the script with the help of Active Screen — instead of having to record all over again
  • Updating the script to make use of parameters instead of the hard-coded values.

Basic QTP Training: Creating our first script

For our Application Under Test (AUT), we made use of the sample application called “Flight” which was bundled with QTP.  We were given the test script that we had to automate. Essentially, the script involved:
1. Logging in
2. Creating an Order
3. Faxing an Order
4. Logging out

To accomplish this, here are the basic steps:
(1) Create a new test by selecting File -> New -> Test from the menu (or CTRL+N).
(2) Update the Record and Run Settings by selecting Automation -> Record and Run Settings… from the menu. We needed to add our AUT in the list of Applications.
(3) Create the script — including steps, checkpoints and output values.

You can try recording the steps and it will be able to produce a script.  However, playing it back will fail due to some hard-coded items that are no longer applicable upon rerunning (e.g., window title included the Order Number which would be different in the next run). It also wouldn’t have the needed checkpoints (or the test/assertions) and it wouldn’t gather output data.

For the first script created, QTP’s record function was used to record the steps. Inserting checkpoints and output values were also done during the recording. For instances wherein the object title or text being checked is dynamic (e.g., window title containing the Order Number), we made use of regular expressions e.g., instead of “Flight No. 19” as originally recorded, we made use of “Flight No.*” with the regular expressions checkbox marked.

Here’s a link to a video recording of the script creation: http://youtu.be/DwayCg1M5IY

Alternatively, here’s a similar script creation video without step 3 though, but it does have audio. It covers basic recording and inserting checkpoints and an output value.

Basic QTP Training: Setup

Earlier today was Day 1 of a 5-day Basic QTP Training that I’m attending at work.  Putting my notes here just in case I have to relearn or I have to echo the training. So initially, we did some setup (see details below), and then there was a demo where a manual test case was automated (will post this separately).

Install HP QuickTest Professional

This involved an installer that was nearly 4GB in size. The setup with the wizard was pretty straightforward. After installing, additional configuration included specifying the license and going to Tools -> Options to modify the Run settings such that the “Allow other HP products to run tests and components” checkbox is marked. This is probably since we’re integrating with HP ALM.

Set up ALM integration

QTP can manage to work on its own, but since we plan to be working with ALM for storing and managing the tests we had to install the following items:

  • ALM Explorer (ALMExplorerAddIn.msi, alternative to viewing ALM in IE)
  • HP Quality Center Connectivity (TDConnect.exe, an ALM add-in)
  • QTP for Business Process Testing (Quick-Test_Add-in_for_ALM-QC.msi)

Selenium Simplified Notes 2 of X

Looking at the code in the previous notes, we can notice that there is one test (annotated with @Test).  That single test does just about everything:

  • It starts an instance of Selenium
  • It does the actions needed to conduct the search
  • It tests for 4 separate things (i.e., whether the result contains a particular text, whether the result contains a particular URL, it checks the page title, and it checks the content of the Search Box field)
  • It closes the browser and stops Selenium

Chapter 12 of the book focuses on refactoring our initial code. End result is that:

  • Separate methods were defined for the set up and tear down activities
  • Each test now only contains code that is relevant to the actual test
  • Initially the @Before and @After annotations were used — These methods will be done before and after each test
  • @BeforeClass and @AfterClass annotations were introduced. But this required some fields and methods to be changed to static so that they can be used across the entire class
package com.eviltester.seleniumtutorials;

import com.thoughtworks.selenium.*;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

public class MySimpleSearchTests {

	static Selenium selenium;

	@BeforeClass
	static public void automateTestSetup() {
		selenium = startSeleniumAndSearch();
	}

	@Test
	public void checkTextIsPresent() {
		assertTrue(selenium.isTextPresent("seleniumhq.org"));
		assertTrue("That long text is not found",
				selenium.isTextPresent(
				"Selenium Remote-Control Selenium RC comes in two parts." +
				" A server which automatically launches and kills browsers,"
				));
	}

	@Test
	public void checkUrlsAreFound() {
		int matchingCountTotal = 0;
		matchingCountTotal += selenium.getXpathCount("//a[@href='http://selenium-rc.seleniumhq.org']").intValue();
		matchingCountTotal += selenium.getXpathCount("//a[@href='http://selenium-rc.seleniumhq.org/']").intValue();
		// use starts-with instead
		matchingCountTotal += selenium.getXpathCount("//a[starts-with(@href, 'http://selenium-rc.seleniumhq.org')]").intValue();
		assertTrue("None of those URL were found", matchingCountTotal>0);
	}

	@Test
	public void checkPageTitle() {
		String pageTitle = selenium.getTitle();
		assertTrue("Search term not found in page title: " + pageTitle,
				pageTitle.contains("Selenium-RC"));
	}

	@Test
	public void checkSearchBox() {
		String searchTerm = selenium.getValue("xpath=//input[@name='q' and @title='Search']");
		assertTrue("Search term not found in search box, contains this instead: " + searchTerm,
				searchTerm.equals("Selenium-RC"));
	}

	@AfterClass
	static public void closeAndStopServer() {
		selenium.close();
		selenium.stop();
	}

	static private Selenium startSeleniumAndSearch() {
		Selenium selenium = new DefaultSelenium("localhost", 4444, "*iexplore", "http://www.compendiumdev.co.uk/");
		selenium.start();
		selenium.open("/selenium/search.php");
		selenium.type("xpath=//input[@name='q']", "Selenium-RC");
		// When we use an XPath starting with '//', we can opt to leave out 'xpath='
		selenium.click("xpath=//input[@name='btnG' and @type='submit']");
		selenium.waitForPageToLoad("30000");
		return selenium;
	}

}

Selenium Simplified Notes 1 of X

So after checking out Alan Richardson’s free course over at udemy, I decided to check out his book.  I bought a digital copy of Selenium Simplified last month and started reading it. The downside of going with a book instead of his video trainings is I don’t get to hear his Irish accent. I try to read it with an accent (but only in my head) but it’s not really working out for me. Anyways, this is the part where I blog about my notes so that many months or years from now, in case I need to relearn what I’ve learned so far, I’ll just refer here instead of reading the entire book.

First things first – Setup

  1. Install Firefox (Although I highly suspect, Future Me will already have it installed.)
  2. Install Selenium IDE from Seleniumhq.org
  3. Install Java (Future Me, it might already be installed. Try java -version at the command line to check.)
  4. Install Selenium RC (well, it’s more of just copy the server .jar file and extract the client .zip files)
  5. Install Eclipse IDE for Java Developer
  6. When you create your Java project in Eclipse, you might need to configure your build path to add the server .jar and JUnit.

A simple java class

It’s not refactored. But it shows how to do a simple search and it has some simple assertions.

package com.eviltester.seleniumtutorials;

import com.thoughtworks.selenium.*;
import org.junit.Test;
import static org.junit.Assert.*;

public class MySimpleSearchTests {

@Test
public void searchAndCheckResults() {

Selenium selenium = new DefaultSelenium("localhost", 4444, "*iexplore", "http://www.compendiumdev.co.uk/");
selenium.start();
selenium.open("/selenium/search.php");
selenium.type("xpath=//input[@name='q']", "Selenium-RC");
// When we use an XPath starting with '//', we can opt to leave out 'xpath='
selenium.click("xpath=//input[@name='btnG' and @type='submit']");
selenium.waitForPageToLoad("30000");

// Now here are the tests...
// Check if particular text is present
assertTrue(selenium.isTextPresent("seleniumhq.org"));
assertTrue("That long text is not found",
selenium.isTextPresent(
"Selenium Remote-Control Selenium RC comes in two parts." +
" A server which automatically launches and kills browsers,"
));

// Check if particular URLs are found
int matchingCountTotal = 0;
matchingCountTotal += selenium.getXpathCount("//a[@href='http://selenium-rc.seleniumhq.org']").intValue();
matchingCountTotal += selenium.getXpathCount("//a[@href='http://selenium-rc.seleniumhq.org/']").intValue();
// use starts-with instead
matchingCountTotal += selenium.getXpathCount("//a[starts-with(@href, 'http://selenium-rc.seleniumhq.org')]").intValue();
assertTrue("None of those URL were found", matchingCountTotal>0);

// Check if page title contains a particular text
String pageTitle = selenium.getTitle();
assertTrue("Search term not found in page title: " + pageTitle,
pageTitle.contains("Selenium-RC"));

// Check if the search box contains the search term
String searchTerm = selenium.getValue("xpath=//input[@name='q' and @title='Search']");
assertTrue("Search term not found in search box, contains this instead: " + searchTerm,
searchTerm.equals("Selenium-RC"));

selenium.close();
selenium.stop();

}

}

Start and stop the Selenium server

Don’t forget to start this up before running your test. Run this at the command line: java -jar selenium-server-standalone-2.33.0.jar To stop, just CTRL+C while at the command window. Or use this at your browser: http://localhost:4444/selenium-server/driver/?cmd=shutDownSeleniumServer