Tag Archives: unittest

A Multi-Layered Test Cake

Dobos layered cake*

A recurrent theme in software engineering are the multiple layers (or tiers) into which systems are subdivided. In the ideal case, a given layer only interacts with the immediate layers “above” and “below” it. In practice, that clean separation of responsibilities is not always possible or, some may argue, desirable.

Nevertheless, thinking in terms of layers is quite useful. For example, the database application I’ve been presenting in this series consists of a PostgreSQL database, psycopg2 (a Python DB-API adapter for PostgreSQL), a business logic module that calls on psycopg2, Werkzeug (a WSGI library), the application modules that call on the business logic and Werkzeug, the HTTP protocol, and the user’s web browser.

As application developers, we need not concern ourselves with the details of how PostgreSQL stores the data that we send to it, nor with testing its internal functions. We rely on PG hackers to cover that testing. Similarly, we rely on Psycopg2 programmers to test communications with PostgreSQL and the Werkzeug team to test its WSGI and HTTP-related functionality. We do have responsibility for testing the business logic, the application code, and the interface presented to the user via the browser.

Tag v0.4.1 of the Database UI Tutorial at GitHub adds a set of unit tests for exercising the business logic module (i.e., werkzeug/bl/film.py). The test module (werkzeug/tests/bl/test_film.py) is pretty straightforward: there is a test method for each method in the business logic class. In addition, there are methods for verifying failure conditions, such as duplicate inserts or deleting a missing record.

Although the unit tests were written after the business logic module (i.e., not in keeping with test-driven development), they helped to resolve an open design issue. Earlier, some methods in dblib.py (thin interface to psycopg2) took an “expected count” argument to check the number of rows affected by a database operation. That didn’t look right, so I had removed it.  While developing the unit tests, it became clear that the checks ought to live in the business logic layer.

Tag v0.4.2 adds unit tests for testing the WSGI or web interface. I was very pleased with how easy it was to use Werkzeug’s testing faciities, Client and BaseResponse, to create the tests: simply “drop” the database app instance into the Client and then call its get or post methods to get the response headers and data. I only had to add the standard library’s xml.dom.minidom to examine particular elements in the HTML body.

Both the business logic and web test modules depend on a utility module which is “reheated” from the Pyrseas version control testing. A nice capability is that the base DbAppTestCase, in its setUpClass method (a Python 2.7 feature), ensures the test database is in sync with the YAML spec.

Coming up: testing the user (browser) interface, via Selenium.


* Dobos cake photograph, courtesy of Bruce Tuten.

Python Development Tools of the Trade

Last week, Bruce Momjian commented that pgindent is one of the reasons for the clarity of the PostgreSQL source code. Today, Andrew Dunstan remarked on “how cleanly it compiles” and no doubt this is due in great part to the buildfarm. So I thought I’d reflect on the tools I’ve been using to ensure the clarity and quality of the Pyrseas code.

Editors

Early in my career, I had a brief encounter with TECO. I also encountered Brief (but for a longer time). Perhaps that explains why, after many years of using vi and vim, in the past few years I’ve gone back to my roots, if you will, and I’m using Emacs for programming.

Some of the Emacs features I find helpful or convenient in developing quality code include (in no particular order):

  • Syntax highlighting: Whether it’s Python, ReStructured Text for the Sphinx documentation, or C in the PostgreSQL code, syntax coloring is nearly always on, by default based on the filename extension.
  • Parentheses matching: Not only for parens, but also for brackets and braces (particularly helpful when creating or editing Python dicts and JSON/YAML maps).
  • which-func-mode: Being able to tell which function/method you’re editing, on the status line, when the head of the function may not be in view.
  • Git branch: Shows in what branch you’re editing, again on the status line. For Subversion, it shows SVN-nnn where nnn is the revision number that last affected the current file.

Unit Testing

I have used the Python unittest testing framework, almost religiously, to develop tests before writing code. I initially also looked at py.test and briefly at nose, but decided the standard library module was good enough. The unit tests have been invaluable when adding features or refactoring code.

Version Control

Git was my choice for a VCS. Two Git features are worth mentioning. One is the change coloring in git diff, but also the context information, e.g., it shows the Python class in which the difference occurs. Second is the ability to stash away work in progress.

Code Quality

I’ve been using pep8 to ensure the Pyrseas code follows as much as possible the Python Style Guide. This is the tool closest to pgindent, but it doesn’t reformat the code.

Lastly, before making the code available publicly, I ran pylint against it. Then I edited it accordingly to improve readability and to eliminate some warning categories.