Helpers for unit testing Glashammer applications
| copyright: | 2008-2009 Glashammer Developers |
|---|---|
| license: | MIT |
This module is presented as a py.test plugin. It provides two main features:
- Provide a method to extract Application unit tests from declarative Yaml files, and
- Provide an easily usable temporary application instance, for standard unit tests.
py.test has a number of hooks that can be accessed to extend its behaviour. This plugin uses the pytest_collect_file hook which is called wih every file available in the test target. The first action of the hook-handler is that it checks if the filename is of the form test*.yml, thus ignoring other Yaml files used for configuration etc.
If it finds an appropriate file, the hook-handler will generate a number of tests based on that file. py.test provides a hierarchical system of tests. The top-level of this hierarchy is an object representing the Yaml file itself. The lower components are represented by further test containers, and subsequent individual tests.
In order to describe the test hierarchy created, we must first take a look at an example declaration of a single Yaml file:
test_index:
path: /
assert_status: 200
test_new:
- path: /new
assert_status: 200
- path: /new
method: POST
data:
text: newpage
assert_status: 302
The file contains two use-cases, the first test_index with a single target, and the second test_new with two targets. Each target contains a single assert. This hierarchy is reflected in the structure of the test hierarchy created for py.test:
YamlTestFile
- TargetTestItem
- ConstraintTest
Each component of the test hierarchy should be a subclass of py.test.collect.Item, which is either a direct subclass, for leaf tests, implementing runtest() or a py.test.collect.File which implements collect() and returns a list of items. In this hierarchy, only the ConstraintTest is an actual leaf test, and each one represesents a single assert_ in the Yaml declaration. In our example above that is assert_status which asserts that the response status code is the numerical value given.
This hierarchy may seem overly complicated, but it is specifically designed to accomodate the sharing of the various tested components. Each UsecaseTestItem in a YamlTestFile has it’s own glashammer.application.GlashammerApplication instance, which each of the TargetTestItem share. This is important to note in that there is persistence between the individual targets within a UsecaseTestItem. Because of this it allows sequential testing of targets, rather than just single isolated tests. The TargetTestItem has any number of ConstraintTest, one for each assert_ key in the target configuration. Each of these map to a single test, which share the response of the TargetTestItem’s path. This way, multiple tests are generated against the single response.
So, within a UsecaseTestItem each TargetTestItem shares the same GlashammerApplication, and within a TargetTestItem, each ConstraintTest shares the same Response. It is important to keep this in mind when writing tests. If a test needs a fresh Application, it should probably be in a different UsecaseTestItem.
Collection hook for py.test
This collection hook looks for Yaml files which may contain tests. The files themselves must be of the glob: test*.yml. Once discovered the test files are collected into a multiple hierarchy of py.test.collect.Item which is described in detail in the module documentation.
tmpapp Funcarg for py.test
This funcarg is a factory, that when called with an optional Glashammer application setup callable, creates a Glashammer Application instance that is bound to py.test’s temporary directory.
Additionally, once tmpapp has been called to create the application, the application itself, and the funcarg each have one additional attribute: client that is a werkzeug.test.Client instance bound to the application.
The tmpapp itself is an instance of AppTestingFactory.