summaryrefslogtreecommitdiff
path: root/README.unittests.rst
blob: 60a64902603eadf3f17c115ff58c30953fd5123d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
================================
SQLALCHEMY / ALEMBIC UNIT TESTS
================================

Alembic makes use of SQLAlchemy's test framework for its test suite,
so working with Alembic's suite is similar to that of working with
SQLAlchemy.

This document is mostly copied directly from that of SQLAlchemy.  Note that
Alembic's test suite currently has "backend" tests (e.g., tests that require a
real database) only for PostgreSQL  and MySQL; other backends like Oracle and
SQL Server are not required.


Basic Test Running
==================

Tox is used to run the test suite fully.   For basic test runs against
a single Python interpreter::

    tox

Advanced Tox Options
====================

For more elaborate CI-style test running, the tox script provided will
run against various Python / database targets.   For a basic run against
Python 2.7 using an in-memory SQLite database::

    tox -e py27-sqlite

The tox runner contains a series of target combinations that can run
against various combinations of databases.  The test suite can be
run against SQLite with "backend" tests also running against a PostgreSQL
database::

    tox -e py36-sqlite-postgresql

Or to run just "backend" tests (NOTE: Alembic has no tests marked this
way so this option is not important) against a MySQL databases::

    tox -e py36-mysql-backendonly

Running against backends other than SQLite requires that a database of that
vendor be available at a specific URL.  See "Setting Up Databases" below
for details.

The py.test Engine
==================

The tox runner is using py.test to invoke the test suite.   Within the realm of
py.test, SQLAlchemy itself is adding a large series of option and
customizations to the py.test runner using plugin points, to allow for
SQLAlchemy's multiple database support, database setup/teardown and
connectivity, multi process support, as well as lots of skip / database
selection rules.

Running tests with py.test directly grants more immediate control over
database options and test selection.

A generic py.test run looks like::

    py.test -n4

Above, the full test suite will run against SQLite, using four processes.
If the "-n" flag is not used, the pytest-xdist is skipped and the tests will
run linearly, which will take a pretty long time.

The py.test command line is more handy for running subsets of tests and to
quickly allow for custom database connections.  Example::

    py.test --dburi=postgresql+psycopg2://scott:tiger@localhost/test  test/sql/test_query.py

Above will run the tests in the test/sql/test_query.py file (a pretty good
file for basic "does this database work at all?" to start with) against a
running PostgreSQL database at the given URL.

The py.test frontend can also run tests against multiple kinds of databases at
once - a large subset of tests are marked as "backend" tests, which will be run
against each available backend, and additionally lots of tests are targeted at
specific backends only, which only run if a matching backend is made available.
For example, to run the test suite against both PostgreSQL and MySQL at the
same time::

    py.test -n4 --db postgresql --db mysql


Setting Up Databases
====================

The test suite identifies several built-in database tags that run against
a pre-set URL.  These can be seen using --dbs::

    $ py.test --dbs
    Available --db options (use --dburi to override)
                 default    sqlite:///:memory:
                firebird    firebird://sysdba:masterkey@localhost//Users/classic/foo.fdb
                   mssql    mssql+pyodbc://scott:tiger@ms_2008
           mssql_pymssql    mssql+pymssql://scott:tiger@ms_2008
                   mysql    mysql://scott:tiger@127.0.0.1:3306/test?charset=utf8
                  oracle    oracle://scott:tiger@127.0.0.1:1521
                 oracle8    oracle://scott:tiger@127.0.0.1:1521/?use_ansi=0
                  pg8000    postgresql+pg8000://scott:tiger@127.0.0.1:5432/test
              postgresql    postgresql://scott:tiger@127.0.0.1:5432/test
    postgresql_psycopg2cffi postgresql+psycopg2cffi://scott:tiger@127.0.0.1:5432/test
                 pymysql    mysql+pymysql://scott:tiger@127.0.0.1:3306/test?charset=utf8
                  sqlite    sqlite:///:memory:
             sqlite_file    sqlite:///querytest.db

What those mean is that if you have a database running that can be accessed
by the above URL, you can run the test suite against it using ``--db <name>``.

The URLs are present in the ``setup.cfg`` file.   You can make your own URLs by
creating a new file called ``test.cfg`` and adding your own ``[db]`` section::

    # test.cfg file
    [db]
    my_postgresql=postgresql://username:pass@hostname/dbname

Above, we can now run the tests with ``my_postgresql``::

    py.test --db my_postgresql

We can also override the existing names in our ``test.cfg`` file, so that we
can run with the tox runner also::

    # test.cfg file
    [db]
    postgresql=postgresql://username:pass@hostname/dbname

Now when we run ``tox -e py27-postgresql``, it will use our custom URL instead
of the fixed one in setup.cfg.

Database Configuration
======================

Step one, the **database chosen for tests must be entirely empty**.  A lot
of what SQLAlchemy and Alembic test is creating and dropping lots of tables
as well as running database introspection to see what is there.  If there
are pre-existing tables or other objects in the target database already,
these will get in the way.   A failed test run can also be followed by
 a run that includes the "--dropfirst" option, which will try to drop
all existing tables in the target database.

The above paragraph changes somewhat when the multiprocessing option
is used, in that separate databases will be created instead, however
in the case of Postgresql, the starting database is used as a template,
so the starting database must still be empty.

The test runner will by default create and drop tables within the default
database that's in the database URL, *unless* the multiprocessing option is in
use via the py.test "-n" flag, which invokes pytest-xdist.   The
multiprocessing option is **enabled by default** when using the tox runner.
When multiprocessing is used, the SQLAlchemy testing framework will create a
new database for each process, and then tear it down after the test run is
complete.    So it will be necessary for the database user to have access to
CREATE DATABASE in order for this to work.

Several tests require alternate usernames or schemas to be present, which are
used to test dotted-name access scenarios.  On some databases such as Oracle or
Sybase, these are usernames, and others such as PostgreSQL and MySQL they are
schemas (created using CREATE SCHEMA).   The requirement applies to all
backends except SQLite and Firebird.  The names are::

    test_schema
    test_schema_2 (only used on PostgreSQL)

Please refer to your vendor documentation for the proper syntax to create
these namespaces - the database user must have permission to create and drop
tables within these schemas.  Its perfectly fine to run the test suite
without these namespaces present, it only means that a handful of tests which
expect them to be present will fail.

Additional steps specific to individual databases are as follows::

    POSTGRESQL: To enable unicode testing with JSONB, create the
    database with UTF8 encoding::

        postgres=# create database test with owner=scott encoding='utf8' template=template0;

    To include tests for HSTORE, create the HSTORE type engine::

        postgres=# \c test;
        You are now connected to database "test" as user "postgresql".
        test=# create extension hstore;
        CREATE EXTENSION

    Full-text search configuration should be set to English, else
    several tests of ``.match()`` will fail. This can be set (if it isn't so
    already) with:

     ALTER DATABASE test SET default_text_search_config = 'pg_catalog.english'

    ORACLE: a user named "test_schema" is created in addition to the default
    user.

    The primary database user needs to be able to create and drop tables,
    synonyms, and constraints within the "test_schema" user.   For this
    to work fully, including that the user has the "REFERENCES" role
    in a remote schema for tables not yet defined (REFERENCES is per-table),
    it is required that the test the user be present in the "DBA" role:

        grant dba to scott;

    MSSQL: Tests that involve multiple connections require Snapshot Isolation
    ability implemented on the test database in order to prevent deadlocks that
    will occur with record locking isolation. This feature is only available
    with MSSQL 2005 and greater. You must enable snapshot isolation at the
    database level and set the default cursor isolation with two SQL commands:

     ALTER DATABASE MyDatabase SET ALLOW_SNAPSHOT_ISOLATION ON

     ALTER DATABASE MyDatabase SET READ_COMMITTED_SNAPSHOT ON


CONFIGURING LOGGING
-------------------
SQLAlchemy logs its activity and debugging through Python's logging package.
Any log target can be directed to the console with command line options, such
as::

    $ ./py.test test/orm/test_unitofwork.py -s \
      --log-debug=sqlalchemy.pool --log-info=sqlalchemy.engine

Above we add the py.test "-s" flag so that standard out is not suppressed.


DEVELOPING AND TESTING NEW DIALECTS  (SQLAlchemy Only)
-------------------------------------------------------

See the file README.dialects.rst for detail on dialects.