Headless browser

Some headless browser for test automation

  • Guillotine – A .NET headless browser, written in C#
  • PhantomJS – a headless WebKit scriptable with a JavaScript API
  • Zombie – Insanely fast, full-stack, headless browser testing using node.js
  • CasperJS – a navigation scripting & testing utility for PhantomJS and SlimerJS
  • HeadlessBrowser – headless browser, for testing the DOM on Node.js
  • SlimerJS – a scriptable browser for Web developers
  • trifleJS – a headless Internet Explorer browser using the .NET
  • Jabba-Webkit – a headless webkit browser for scraping AJAX
  • HtmlUnit – a GUI-Less browser for Java programs
  • Awesomium – HTML UI Engine for C++ and .NET
  • env.js – a pure JavaScript browser environment

Extend SSH Sessions on Mac OS

On Mac OS, SSH sessions to remote computers are timing out too quickly! The solution is to set a timeout interval in seconds.

Steps

# create configuration file for SSH
$ touch ~/.ssh/config

# edit the file
$ vim ~/.ssh/config

# add following content and save
ServerAliveInterval 120

Create your own REST testing application

This time i want show you how to create your own REST testing application. For this demonstration i use Python, Tkinter and some Python libraries. At the end of this tutorial you can extend the application with more features like “show headers”, “store requests/responses”, “run automatically” and so on.

Preparation

  • install Python > 2.7 (Tkinter included)
  • install Requests: HTTP for Humans
  • install Python Data Validation for Humans
requests==2.8.1
validators==0.9

Example

# -*- coding: utf-8 -*-
from Tkinter import Tk, FALSE


class BaseTkGui(object):
    """Define basic TK GUI"""

    def __init__(self, window_title, window_resizable):
        """Constructor for Tkinter GUI"""

        self._root = Tk()
        self._root.title(str(window_title))

        if not bool(window_resizable):
            self._root.resizable(width=FALSE, height=FALSE)
        else:
            self._root.columnconfigure(0, weight=1)
            self._root.rowconfigure(0, weight=1)

    def start_app(self):
        """Start TK loop"""

        self._root.mainloop()

    def quit_app(self):
        """Stop and quit application"""

        self._root.quit()
# -*- coding: utf-8 -*-
from Tkinter import (Frame, OptionMenu, Entry, Button, StringVar, Label,
                     W, E, NO, END, SOLID)
from ttk import Treeview, Separator
from ScrolledText import ScrolledText
from BaseGui import BaseTkGui


class ApplicationTkGui(BaseTkGui):
    """Define application TK GUI"""

    OPTIONS = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS']

    def __init__(self, window_title):
        """Constructor for specific application GUI"""

        BaseTkGui.__init__(self, window_title, False)

        self._method = None
        self._url = None
        self._tree = None
        self._status = None
        self._time = None
        self._key = None
        self._value = None
        self._output = None

    def build_frames(self):
        """Add all frames and start mainloop"""

        self.__top_frame()
        self.__middle_frame()
        self.__bottom_frame()

        self.start_app()

    def prepare_req(self):
        """Overwritten method"""

        pass

    def _add_items(self):
        """Add items into TreeView at end"""

        key = str(self._key.get())
        value = str(self._value.get())

        if key and value:
            self._tree.insert("", "end", values=(key, value))
            self._key.delete(0, END)
            self._value.delete(0, END)

        self._tree.bind("<Double-1>", self._delete_item)

    def _delete_item(self, event):
        """Delete items from TreeView by ID"""

        item = self._tree.identify_row(event.y)
        self._tree.delete(item)

    def __top_frame(self):
        """Top frame creator"""

        self._method = StringVar(self._root)
        self._method.set("GET")

        frame = Frame(self._root)
        frame.grid(column=0, row=0, sticky=W+E)
        frame.grid_rowconfigure(0, weight=1)
        frame.grid_columnconfigure(0, weight=1)

        option = OptionMenu(frame, self._method, *self.OPTIONS)
        option.grid(column=0, row=0, padx=5, pady=5)

        self._url = Entry(frame, width=50)
        self._url.grid(column=1, row=0, padx=5, pady=5)
        self._url.configure(borderwidth=1, relief=SOLID)
        self._url.configure(highlightthickness=0)
        self._url.insert(0, 'http://')

        submit = Button(frame, text='Submit', command=self.prepare_req)
        submit.grid(column=3, row=0, padx=5, pady=5)

        Separator(frame).grid(columnspan=4, row=1, sticky=W+E)

    def __middle_frame(self):
        """Middle frame creator"""

        frame = Frame(self._root)
        frame.grid(column=0, row=1, sticky=W+E)
        frame.grid_rowconfigure(0, weight=1)
        frame.grid_columnconfigure(0, weight=1)

        self._tree = Treeview(frame, columns=("Key", "Val"), selectmode='none')
        self._tree.grid(columnspan=5, row=0, padx=5, pady=5, sticky=W+E)
        self._tree.column('#0', stretch=NO, minwidth=0, width=0)
        self._tree.heading('#1', text='Key')
        self._tree.heading('#2', text='Value')
        self._tree.configure(height=5)

        key = Label(frame, text='Key:')
        key.grid(column=0, row=1, padx=5, pady=5, sticky=E)
        self._key = Entry(frame)
        self._key.grid(column=1, row=1, padx=5, pady=5, sticky=W)
        self._key.configure(borderwidth=1, relief=SOLID)
        self._key.configure(highlightthickness=0)

        value = Label(frame, text='Value:')
        value.grid(column=2, row=1, padx=5, pady=5, sticky=E)
        self._value = Entry(frame)
        self._value.grid(column=3, row=1, padx=5, pady=5, sticky=W)
        self._value.configure(borderwidth=1, relief=SOLID)
        self._value.configure(highlightthickness=0)

        add = Button(frame, text='Add new header', command=self._add_items)
        add.grid(column=4, row=1, padx=5, pady=5)

        Separator(frame).grid(columnspan=5, row=2, sticky=W+E)

    def __bottom_frame(self):
        """Bottom frame creator"""
        font_style = ('verdana', 10, 'normal')

        frame = Frame(self._root)
        frame.grid(column=0, row=2, sticky=W+E)
        frame.grid_rowconfigure(0, weight=1)
        frame.grid_columnconfigure(0, weight=1)

        self._status = Label(frame, text='Response Status: -')
        self._status.grid(column=0, row=0, sticky=W)
        self._status.configure(fg='red', font=font_style)

        self._time = Label(frame, text='Time: - ms')
        self._time.grid(column=1, row=0, sticky=E)
        self._time.configure(fg='red', font=font_style)

        self._output = ScrolledText(frame)
        self._output.grid(columnspan=2, row=1, padx=5, pady=5, sticky=W+E)
        self._output.configure(height=12, borderwidth=1, relief=SOLID)
        self._output.configure(highlightthickness=0)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
import validators
from Tkinter import END
from ApplicationGui import ApplicationTkGui


class Application(ApplicationTkGui):
    """Define application behaviors"""

    def __init__(self, window_title):
        """Constructor for application with title"""

        ApplicationTkGui.__init__(self, window_title)

    def run_application(self):
        """Start application"""

        self.build_frames()

    def prepare_req(self):
        """Prepare and validate request"""

        headers = dict()
        method = self._method.get()
        url = self._url.get()
        tree_ids = self._tree.get_children()

        for i in tree_ids:
            row = self._tree.item(i)
            add = row['values']
            headers[add[0]] = add[1]

        if validators.url(url):
            self.__do_request(method, url, headers)

    def __do_request(self, method, url, headers):
        """Do request and print results"""

        self._output.delete(1.0, END)

        ses = requests.Session()
        prepped = requests.Request(method, url, headers).prepare()
        response = ses.send(prepped, verify=False, allow_redirects=True)

        code = response.status_code
        body = response.text
        time_delta = response.elapsed
        duration = time_delta.total_seconds()

        status = 'Response Status: ' + str(code)
        time = 'Time: ' + str(duration) + ' ms'
        text = body[0:900] + ' ...'

        self._status.configure(text=status)
        self._time.configure(text=time)
        self._output.insert(END, text)

if __name__ == '__main__':

    RUN = Application('HTTPTester')
    RUN.run_application()

Run application

# set access permissions
$ chmod u+x ./RESTme.py
 
# start application
$ python -B ./RESTme.py

The application should look like:

RESTme Application

Create your own fake-data generator application

In this episode i want to show you, how easy it is to create a fake-data generator application.

Why?

  1. to get inspired
  2. if you need such tool behind restricted areas (without internet)
  3. software testers need a lot of fake-data

Required

  • Python > 2.7
  • Python Faker package installed
# install by pip
$ sudo pip install fake-factory

Example Application Code

# -*- coding: utf-8 -*-
from faker import Factory


class BasicGenerator(object):

    SETTINGS = ('Prefix', 'Name', 'Address', 'E-Mail', 'Phone',
                'Birthday', 'Company')

    def __init__(self):
        """Constructor for vars and factory object"""
        self._repeat_count = None
        self._selection = None
        self.__faker = Factory.create()

    def faker_data(self, count, selection):
        """Return fake data string"""
        output = str()
        loops = int(count)
        value = tuple(selection)
        for i in range(0, loops):
            if 0 in value:
                output += self.__faker.prefix()
            if 1 in value:
                output += self.__faker.name() + '\n'
            if 2 in value:
                output += self.__faker.address() + '\n'
            if 3 in value:
                output += self.__faker.email() + '\n'
            if 4 in value:
                output += self.__faker.phone_number() + '\n'
            if 5 in value:
                output += self.__faker.date() + '\n'
            if 6 in value:
                output += self.__faker.company() + '\n'
            output += '\n'
        return output
# -*- coding: utf-8 -*-
from BasicGenerator import BasicGenerator
from Tkinter import (Tk, Button, Variable, Listbox, MULTIPLE, FALSE, END,
                     Spinbox, E, W)
from ScrolledText import ScrolledText


class FakeNameGenerator(BasicGenerator):

    def __init__(self):
        """Constructor for Tkinter GUI"""
        BasicGenerator.__init__(self)
        self.__root = Tk()
        self.__root.title('FakeNameGenerator')
        self.__root.resizable(width=FALSE, height=FALSE)
        self.__result_output = None
        self.__box_opt = Variable(self.__root)
        self.__box_opt.set(self.SETTINGS)

    def start_app(self):
        """Build widgets and start TK loop"""
        self.__control_widget()
        self.__output_widget()
        self.__root.mainloop()

    def quit_app(self):
        """Stop and close application"""
        self.__root.quit()

    def __reset_output(self):
        """Reset TK text"""
        self.__result_output.delete(1.0, END)

    def __run_fake_data(self):
        """Validate and generate output"""
        count = int(self._repeat_count.get())
        selection = self._selection.curselection()
        if not selection:
            self.__result_output.insert(END, 'No value selected!\n\n')
        elif count < 1:
            self.__result_output.insert(END, 'Min. 1 need!\n\n')
        elif count > 10:
            self.__result_output.insert(END, 'Max. 10 allowed!\n\n')
        else:
            data = self.faker_data(count, selection)
            self.__result_output.insert(END, data)

    def __control_widget(self):
        """Build control widgets"""
        self._selection = Listbox(self.__root,
                                  listvariable=self.__box_opt,
                                  selectmode=MULTIPLE)
        self._selection.grid(padx=5, column=1, row=1, sticky=W+E)
        self._repeat_count = Spinbox(self.__root,
                                     from_=1,
                                     to=10)
        self._repeat_count.grid(column=1, row=2, sticky=W+E)
        Button(self.__root,
               text='Create',
               command=self.__run_fake_data).grid(column=1, row=3, sticky=W+E)
        Button(self.__root,
               text='Reset',
               command=self.__reset_output).grid(column=1, row=4, sticky=W+E)
        Button(self.__root,
               text='Quit',
               command=self.quit_app).grid(column=1, row=6, sticky=W+E)

    def __output_widget(self):
        """Build output widget"""
        self.__result_output = ScrolledText(self.__root, width=80)
        self.__result_output.grid(padx=5, pady=5, column=0, row=0, rowspan=7)
        self.__result_output.config(borderwidth=1, highlightthickness=1)


if __name__ == '__main__':
    RUN = FakeNameGenerator()
    RUN.start_app()

Run Fake-Data Application

# set access permissions
$ chmod u+x FakeNameGenerator.py

# start application
$ python -B ./FakeNameGenerator.py

Now it`s on you to improve this tiny application! As example you could add file and/or database export, add more functionality or just improve the GUI.

htop the process viewer

htop is a interactive process viewer like top. The installing and using on different systems is super simple. The advantages over standard top are:

  • fast view on performance statistics
  • process scrolling (vertically)
  • much easier to understand
  • no need to type the process number to kill a process
  • tree view (optional)

Installation

# install on Mac OS via MacPorts
$ sudo port install htop

# install on Debian/Ubuntu/Mint
$ sudo aptitude update
$ sudo aptitude install htop

# install on RHEL/CentOS/Fedora
$ yum update -y
$ yum install -y htop

Usage

# 10 seconds between updates
$ htop -d 10

# show only processes of a given user
$ htop -u <USERNAME>

# sort by this column
$ htop --sort-key <COLUMN>

In the terminal, the use is self-explanatory.

Jenkins and Virtualenv

This guide is intended to show how you can use Jenkins/Hudson with Python virtualenv.

Precondition

Preparation

# install on Debian/Ubuntu/Mint
$ sudo aptitude update
$ sudo aptitude install python-pip python-virtualenv

# install on Mac OS
$ sudo easy_install pip
$ sudo pip install virtualenv

Example

Create (if necessary) a new “Freestyle Project” and configure as needed build-paramaters , VCS and etc. On section “Build” – “Execute Shell” insert following script.

# set variable
ExampleENV="${WORKSPACE}"/.ExampleENV

# delete folder and content if exists
if [ -d "$ExampleENV" ]; then
	rm -fr "$ExampleENV"
fi

# create new virtualenv
virtualenv --no-site-packages "$ExampleENV"

# activate virtualenv
. "$ExampleENV"/bin/activate

# CODE FOR VIRTUALENV...