Software Testing (Definitions and Terms) – part 2

Baseline

A baseline is defined as a single set of data that has been captured for purposes of measuring improvement.

A baseline is a set of captured data to measure improvement. A baseline can be a benchmark, but a benchmark can only be a baseline once. A baseline is generally is generally captured once during a cycle or phase, and future benchmarks are compared to a single baseline.

Methodology

A methodology is a defined set of methods collected to accomplish a goal.

methodology

methodology

In many organizations, the term methodology is commonly used when describing the ways actions are done in the company. These actions are typically executed with certain methods or ways of doing things. Over time, organizations learn from their mistakes and modify these methods, formalize them, and call them their methodology. These collections of methods are often revisited and improved over time.

Process

A process, in terms of software methodology, is a set of related tasks which are compiled to a accomplish a goal.

process

process

Within a methodology, each method defined generally requires a set of tasks that must be completed. These set tasks are called processes. Both a methodology and it’s encompassing processes are created to accomplish a common goal for the organization.

Procedure

A procedure is a set of actions, operations, or methods which are executed the same way each time in order to obtain the same result.

procedure

procedure

Procedures exist within the methodology  to ensure the processes are executed in a consistent manner. These set of steps are defined to complete several tasks to complete certain processes which make up a methodology.

Test Framework

A test framework is a set of concepts, methodologies and tools to support the software testing effort.

test framework

test framework

Test frameworks provide a mechanism for consistent testing procedures around software testing. These repeatable techniques ensure the software testing practices yield reliable results as the organizations matures.

Keyword-driven Testing

Keyword-driven testing is a test methodology which employs action-words to drive events in a test case or script.

keyword-driven testing

keyword-driven testing

As organizations become more test savvy, a methodology known as keyword-driven testing provides an effective mechanism to organize the test scripts into logical components that can be used repeatedly. These components typically consist of an object, an action, and supporting data if required. The methodology usually requires a longer ramp-up period since planning and implementation of the components take time to build and organize. This initial investment pays off since there is an substantial decrease in technical skill requirement to build keyword-driven tests once a framework is in place.

Verification and Validation

verification and validation

verification and validation

Two terms that are commonly used in the software testing world are verification and validation.

Verification is a quality process which ensures a product complies with standards and regulations. Validation on the other hand, ensures the product adheres to established requirements. A quote from Barry Boehm makes this clear; Verification ensures we are producing the product right and Validation ensures we are producing the right product.

Simple hybrid mobile app using cordova and ratchet 2 (complete)

In this tutorial, I will show you how to create a simple app using cordova and ratchet 2.

simple app using ratchet 2

simple app using ratchet 2

Download the required software packages

Download and install Eclipse Juno SR2 and Xcode 5 (if you using Mac for mobile development).

Eclipse Juno SR2 – http://www.eclipse.org/downloads/packages/release/juno/sr2
Xcode 5 – https://developer.apple.com/xcode/downloads/

Setup ADT and Android SDK into your eclipse. You can refer here how to setup, http://blog.revivalx.com/2014/02/21/crud-operation-using-jquery-mobile-on-android-part-1/. Then you need to setup cordova using NPM (node package manager) from that link.

Download Jquery and Ratchet from their official website. You should unzip it to proper location. For this tutorial, we using Jquery 2.1.1 and Ratchet 2.0.2.

Setting up your development environment

Create a cordova project using command below in your terminal/cmd:

cordova create com.revivalx.ratchet
cordova create project

cordova create project

Open config.xml inside com.revivalx.ratchet folder and replace with this code.

config.xml

config.xml

config.xml

<?xml version='1.0' encoding='utf-8'?>
<widget id="com.revivalx.ratchet" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
    <name>CordovaRatchet</name>
    <description>
        A sample Apache Cordova application that responds to the deviceready event.
    </description>
    <author email="mohammadnrdn@gmail.com" href="http://revivalx.com">
        Mohammad Nurdin bin Norazan
    </author>
    <content src="index.html" />
    <access origin="*" />
</widget>

Add platform for iOS and android.

cordova platform add ios
cordova platform add android
cordova platform add android

cordova platform add android

cordova platform add ios

cordova platform add ios

Create a new project inside your eclipse.

create a new eclipse project

create a new eclipse project

Select General > Project.

new eclipse project

new eclipse project

Enter following details and click Finish.

Project name: com.revivalx.ratchet.

Location: your project location.

create a new eclipse project

create a new eclipse project

 Overview of Cordova directory structures

Here is the Cordova directory structure:

cordova structure

cordova structure

hooks – This directory may contains scripts used to customize cordova commands.

platforms (android and iOS) – Platforms added to your application will have the native application project structures laid out within this directory.

plugins – Any added plugins will be extracted or copied into this directory.

www (css) – The main application CSS directory.

www (img) – The main application image directory.

www (js) – The main application javascript directory.

index.html – The main HTML file.

config.xml – A global configuration file.

Preview your app (android)

Import android project into your eclipse.

import cordova project

import cordova project

Select AndroidExisting Android Code Into Workspace.

import existing android code into workspace

import existing android code into workspace

Browse your project and click Finish.

import android project

import android project

Follow this tutorial how to run android app in android simulator.

http://blog.revivalx.com/2014/02/21/crud-operation-using-jquery-mobile-on-android-part-1/

Preview your app (ios)

Go to your project directory and browse for xcode project, platforms > ios > CordovaRatchet.xcodeproj then run xcode project.

xcode project

xcode project

Click Play on top left side to preview the app on your simulator.

xcode project

xcode project

Learning client side API and building a multi page application

Right click js folder on your project. Go to New > Javascript Source File.

Javascript Source File

Javascript Source File

Select JavaScript > JavaScript Source File and click Next.

javascript source file

javascript source file

Create 3 javascript files.

  • main.js – initialize function.
  • AddPage.js – to add user details.
  • ListPage.js – to retrieve user list.
  • DetailPage.js – to retrieve user details.

Click Finish.

javascript source file

javascript source file

Right click www folder and go to New > Folder to create a new folder.

add folder

add folder

Name it pages and click Finish.

add folder pages

add folder pages

Then create a few of html pages inside page folder that we already created just now. Right click pages folder and go to New > HTML File.

HTML Files

HTML Files

Select Web > HTML File and click Next.

new html file

new html file

Create 3 html files and click Finish. Repeat.

  • AddPage.html – to add user details.
  • ListPage.html – to retrieve user list.
  • DetailPage.html – to retrieve user details.
new html file

new html file

Copy Jquery javascript files that you already extract from proper location into js folder.

jquery

jquery

Go to extracted Ratchet directory and select/copy all folders inside ratchet-2.0.2 > dist .

ratchet directory

ratchet directory

Then paste it inside www folder.

ratchet

ratchet

Open your index.html and replace with this code.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>

    <!-- Sets initial viewport load and disables zooming  -->
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">

    <!-- Makes your prototype chrome-less once bookmarked to your phone's home screen -->
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">

    <!-- Include the compiled Ratchet CSS -->
    <link href="css/ratchet.css" rel="stylesheet">
    <script src="cordova.js" type="text/javascript"></script>
    <script src="js/jquery-2.1.1.min.js"></script>
    <script src="js/ratchet.js"></script>
    <script src="js/main.js"></script>
  </head>
  <body onload="init()">

  </body>
</html>

Replace all codes with given codes for each javascript files.

AddPage.js

currentPage={};

currentPage.init = function() {
    console.log("AddPage :: init");
};

currentPage.back = function(){
    console.log("AddPage :: back");
    $("body").load(path + "pages/ListPage.html", function(){
        $.getScript(path + "js/ListPage.js", function() {
            if (currentPage.init) {
                currentPage.init();
            }
        });
    });
};

DetailPage.js

currentPage={};

currentPage.init = function() {
    console.log("DetailPage :: init");
};

currentPage.back = function(){
    console.log("DetailPage :: back");
    $("body").load(path + "pages/ListPage.html", function(){
        $.getScript(path + "js/ListPage.js", function() {
            if (currentPage.init) {
                currentPage.init();
            }
        });
    });
};

ListPage.js

currentPage = {};

currentPage.init = function(){
    console.log("ListPage :: init");
};

currentPage.loadPage = function(pageIndex){
    console.log("ListPage :: loadPage :: pageIndex: " + pageIndex);
    $("body").load(path + "pages/" + pageIndex + ".html");
    $.getScript(path + "js/" + pageIndex +".js", function() {
        if (currentPage.init) {
            currentPage.init();
        }
    });
};

main.js

var pagesHistory = [];
var currentPage = {};
var path = "";

function init(){

    $("body").load(path + "pages/ListPage.html", function(){
        $.getScript(path + "js/ListPage.js", function() {
            if (currentPage.init) {
                currentPage.init();
            }
        });
    });

}

Replace all codes with given codes for each html files.

AddPage.html

<script>
    $.getScript(path + "js/AddPage.js");
</script>

<header class="bar bar-nav">
	<a class="icon icon-left-nav pull-left" onclick="currentPage.back();"></a>
  	<h1 class="title">AddPage</h1>
</header>

DetailPage.html

<script>
    $.getScript(path + "js/DetailPage.js");
</script>

<header class="bar bar-nav">
	<a class="icon icon-left-nav pull-left" onclick="currentPage.back();"></a>
  	<h1 class="title">DetailPage</h1>
</header>

ListPage.html

<script>
    $.getScript(path + "js/ListPage.js");
</script>

<header class="bar bar-nav">
	<button id="LoadAddButton" class="btn pull-right" onclick="currentPage.loadPage('AddPage');">Load Add.html</button>
  	<h1 class="title">ListPage</h1>
</header>

<div class="content">
<div class="content-padded">
    <button id="LoadDetailButton" class="btn btn-positive btn-block" onclick="currentPage.loadPage('DetailPage');">Load Detail.html</button>
</div>
</div>

Preview your app using previous steps.

We will using there URLs for our HTTP request/response. Refer to this tutorial for more understanding.

Now we want to integrate PHP with app. You need to replace all html files and js files so we can invoke PHP from there.

AddPage.js

currentPage = {};
currentPage.init = function() {
    console.log("AddPage :: init");
};
currentPage.back = function() {
    console.log("AddPage :: back");
    $("body").load(path + "pages/ListPage.html", function() {
        $.getScript(path + "js/ListPage.js", function() {
            if (currentPage.init) {
                currentPage.init();
            }
        });
    });
};
currentPage.add = function() {
    console.log("AddPage :: add");
    var name = $("#name").val();
    var officeNumber = $("#officeNumber").val();
    var phoneNumber = $("#phoneNumber").val();
    var email = $("#email").val();
    formData = {
        name: $("#name").val(),
        officeNumber: $("#officeNumber").val(),
        phoneNumber: $("#phoneNumber").val(),
        email: $("#email").val()
    }
    if (name == "") {
        alert("Please enter name");
    } else if (officeNumber == "") {
        alert("Please enter office number");
    } else if (phoneNumber == "") {
        alert("Please enter phone number");
    } else if (email == "") {
        alert("Please enter email");
    } else {
        $.ajax({
            type: "get",
            url: "http://demo.revivalx.com/worklight/create_user.php",
            data: formData,
            dataType: "json",
            success: function(data) {
                alert("Add user success");
                $("body").load(path + "pages/ListPage.html", function() {
                    $.getScript(path + "js/ListPage.js", function() {
                        if (currentPage.init) {
                            currentPage.init();
                        }
                    });
                });
            },
            error: function() {
                alert("Add user failure");
            }
        });
    }
};

DetailPage.js

currentPage = {};
currentPage.init = function() {
    console.log("DetailPage :: init");
    detailUser();
};
currentPage.back = function() {
    console.log("DetailPage :: back");
    $("body").load(path + "pages/ListPage.html", function() {
        $.getScript(path + "js/ListPage.js", function() {
            if (currentPage.init) {
                currentPage.init();
            }
        });
    });
};
currentPage.edit = function() {
    console.log("DetailPage :: edit");
    var userId = sessionStorage.userId;
    var name = $("#name").val();
    var officeNumber = $("#officeNumber").val();
    var phoneNumber = $("#phoneNumber").val();
    var email = $("#email").val();
    formData = {
        userId: sessionStorage.userId,
        name: $("#name").val(),
        officeNumber: $("#officeNumber").val(),
        phoneNumber: $("#phoneNumber").val(),
        email: $("#email").val()
    }
    if (name == "") {
        alert("Please enter name");
    } else if (officeNumber == "") {
        alert("Please enter office number");
    } else if (phoneNumber == "") {
        alert("Alert", "Please enter phone number");
    } else if (email == "") {
        alert("Alert", "Please enter email");
    } else {
        $.ajax({
            type: "get",
            url: "http://demo.revivalx.com/worklight/update_user.php",
            data: formData,
            dataType: "json",
            success: function(data) {
                alert("Edit user success");
                $("body").load(path + "pages/ListPage.html", function() {
                    $.getScript(path + "js/ListPage.js", function() {
                        if (currentPage.init) {
                            currentPage.init();
                        }
                    });
                });
            },
            error: function() {
                alert("Edit user failure");
            }
        });
    }
};

function detailUser() {
    formData = {
        userId: sessionStorage.userId
    }
    $.ajax({
        type: "get",
        url: "http://demo.revivalx.com/worklight/get_user_details.php",
        data: formData,
        dataType: "json",
        success: function(data) {
            $('#name').val(data.user[0].name);
            $('#officeNumber').val(data.user[0].officeNumber);
            $('#phoneNumber').val(data.user[0].phoneNumber);
            $('#email').val(data.user[0].email);
        },
        error: function() {
            alert("Detail user failure");
        }
    });
}
currentPage.remove = function() {
    console.log("DetailPage :: delete");
    deleteUser();
};

function deleteUser() {
    formData = {
        userId: sessionStorage.userId
    }
    $.ajax({
        type: "get",
        url: "http://demo.revivalx.com/worklight/delete_user.php",
        data: formData,
        dataType: "json",
        success: function(data) {
            alert("Delete user success");
            $("body").load(path + "pages/ListPage.html", function() {
                $.getScript(path + "js/ListPage.js", function() {
                    if (currentPage.init) {
                        currentPage.init();
                    }
                });
            });
        },
        error: function() {
            alert("Delete user failure");
        }
    });
}

ListPage.js

currentPage = {};
currentPage.init = function() {
    console.log("ListPage :: init");
    listUsers();
};
currentPage.loadPage = function(pageIndex) {
    console.log("ListPage :: loadPage :: pageIndex: " + pageIndex);
    $("body").load(path + "pages/" + pageIndex + ".html");
    $.getScript(path + "js/" + pageIndex + ".js", function() {
        if (currentPage.init) {
            currentPage.init();
        }
    });
};
currentPage.detailPage = function(userId) {
    sessionStorage.setItem("userId", userId);
    $("body").load(path + "pages/DetailPage.html");
    $.getScript(path + "js/DetailPage.js", function() {
        if (currentPage.init) {
            currentPage.init();
        }
    });
};

function listUsers() {
    $.ajax({
        type: "get",
        url: "http://demo.revivalx.com/worklight/get_all_users.php",
        dataType: "json",
        success: function(data) {
            var ul = $('#userList');
            var html = '';
            $.each(data.users, function(index, item) {
                html += '<li class="table-view-cell">';
                html += '<a class="navigate-right" onclick="currentPage.detailPage(' + item.userId + ');" >';
                html += item.name;
                html += '</a></li>';
            });
            ul.append(html);
        },
        error: function() {
            alert("List user failure");
        }
    });
}

AddPage.html

<script>
    $.getScript(path + "js/AddPage.js");
</script>
 
<header class="bar bar-nav">
    <a class="icon icon-left-nav pull-left" onclick="currentPage.back();"></a>
    <h1 class="title">AddPage</h1>
</header>

<div class="content">
	<div class="card">
    <ul class="table-view">
        <li class="table-view-cell table-view-divider">Name:</li>
 
        <li class="table-view-cell"><input id="name" name="name" type="text"></li>
 
        <li class="table-view-cell table-view-divider">Office Number:</li>
 
        <li class="table-view-cell"><input id="officeNumber" name="officeNumber" type="text"></li>
 
        <li class="table-view-cell table-view-divider">Phone Number:</li>
 
        <li class="table-view-cell"><input id="phoneNumber" name="phoneNumber" type="text"></li>
 
        <li class="table-view-cell table-view-divider">Email:</li>
 
        <li class="table-view-cell"><input id="email" name="email" type="text"></li>
 
        <li class="table-view-cell"></li>
    </ul>
   </div>
    <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-positive btn-block" onclick="currentPage.add();">ADD USER</button>
    </div>
</div>

DetailPage.html

<script>
    $.getScript(path + "js/DetailPage.js");
</script>
 
<header class="bar bar-nav">
    <a class="icon icon-left-nav pull-left" onclick="currentPage.back();"></a>
    <h1 class="title">DetailPage</h1>
</header>
 
<div class="content">
	<div class="card">
    <ul class="table-view">
        <li class="table-view-cell table-view-divider">Name:</li>
 
        <li class="table-view-cell"><input id="name" name="name" type="text"></li>
 
        <li class="table-view-cell table-view-divider">Office Number:</li>
 
        <li class="table-view-cell"><input id="officeNumber" name="officeNumber" type="text"></li>
 
        <li class="table-view-cell table-view-divider">Phone Number:</li>
 
        <li class="table-view-cell"><input id="phoneNumber" name="phoneNumber" type="text"></li>
 
        <li class="table-view-cell table-view-divider">Email:</li>
 
        <li class="table-view-cell"><input id="email" name="email" type="text"></li>
    </ul>
   </div>
   <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-positive btn-block" onclick="currentPage.edit();">EDIT USER</button>
   </div>
   <div class="card" style="margin-bottom:40px;">
    	<button class="btn btn-negative btn-block" onclick="currentPage.remove();">REMOVE USER</button>
   </div> 
</div>

ListPage.html

<script>
    $.getScript(path + "js/ListPage.js");
</script>

<header class="bar bar-nav">
	<button id="LoadAddButton" class="btn pull-right" onclick="currentPage.loadPage('AddPage');">Add</button>
  	<h1 class="title">ListPage</h1>
</header>

<div class="content">
	<ul id="userList" class="table-view"></ul>
</div>

Build and run your app. You can find the source code here: https://github.com/datomnurdin/com.revivalx.ratchet

 

Upload image using file-transfer cordova plugin for iOS and android

From previous tutorial, we talk about camera cordova plugin for iOS and android. Users can capture photo or select images from gallery in their phone. Today, I want to share with you how to upload image into server (PHP) using file-transfer cordova plugin for iOS and android.

Create project com.revivalx.cordova.file-transfer and install camera and file-transfer cordova plugin into your cordova project.

cordova create com.revivalx.cordova.file-transfer
cd com.revivalx.cordova.file-transfer
cordova plugin add https://github.com/apache/cordova-plugin-camera
cordova plugin add https://github.com/apache/cordova-plugin-file-transfer
create project

create project

First you need to complete this tutorial first before we go any further. http://blog.revivalx.com/2014/05/03/tutorial-camera-cordova-plugin-for-ios-and-android/ . It is because we want to get an image before upload it into server.

Open up index.html file in www folder. Replace with this code.

<!DOCTYPE html>

<html>
<head>
<meta charset="utf-8">
<meta content="telephone=no" name="format-detection">
<!– WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 –>
<meta content=
"user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi"
name="viewport">
<script src="cordova.js" type="text/javascript"></script>
<script src="js/index.js" type="text/javascript"></script>
<title>Camera Cordova Plugin</title>
</head>

<body>
<button onclick="capturePhoto();">Capture Photo</button><br>
<button onclick="getPhoto(pictureSource.PHOTOLIBRARY);">From Photo
Library</button><br>
<img id="image" src="" style="display:none;width:100%;">
<button onclick="upload();">Upload</button>
</body>
</html>

Then open up index.js file in js folder add this code after onFail function.

function upload() {
    var img = document.getElementById('image');
    var imageURI = img.src;
    var options = new FileUploadOptions();
    options.fileKey = "file";
    options.fileName = imageURI.substr(imageURI.lastIndexOf('/') + 1);
    options.mimeType = "image/jpeg";
    var params = new Object();
    options.params = params;
    options.chunkedMode = false;
    var ft = new FileTransfer();
    ft.upload(imageURI, "https://www.example.com/upload.php", win, fail,
        options);
}

function win(r) {
    console.log("Code = " + r.responseCode);
    console.log("Response = " + r.response);
    console.log("Sent = " + r.bytesSent);
}

function fail(error) {
    alert("An error has occurred: Code = " + error.code);
    console.log("upload error source " + error.source);
    console.log("upload error target " + error.target);
}

Simple upload php code.

<?php
move_uploaded_file($_FILES["file"]["tmp_name"], '/path/to/file');

Build and run the app. I hope you enjoy this article. You may download the source code here, https://github.com/datomnurdin/com.revivalx.cordova.file-transfer .