Add assert_* functions

This commit is contained in:
Konsta Vesterinen
2014-10-23 13:44:49 +03:00
parent ec68aecbb7
commit 24817e909d
6 changed files with 205 additions and 1 deletions

View File

@@ -4,6 +4,12 @@ Changelog
Here you can see the full list of changes between each SQLAlchemy-Utils release.
0.27.4 (2014-10-23)
^^^^^^^^^^^^^^^^^^^
- Added assert_non_nullable, assert_nullable and assert_max_length testing methods
0.27.3 (2014-10-22)
^^^^^^^^^^^^^^^^^^^

View File

@@ -20,4 +20,5 @@ SQLAlchemy-Utils provides custom data types and various utility functions for SQ
orm_helpers
utility_classes
models
testing
license

20
docs/testing.rst Normal file
View File

@@ -0,0 +1,20 @@
Testing
=======
.. automodule:: sqlalchemy_utils.asserts
assert_nullable
---------------
.. autofunction:: assert_nullable
assert_non_nullable
-------------------
.. autofunction:: assert_non_nullable
assert_max_length
-----------------
.. autofunction:: assert_max_length

View File

@@ -1,4 +1,5 @@
from .aggregates import aggregated
from .asserts import assert_nullable, assert_non_nullable, assert_max_length
from .batch import batch_fetch, with_backrefs
from .decorators import generates
from .exceptions import ImproperlyConfigured
@@ -78,12 +79,15 @@ from .types import (
from .models import Timestamp
__version__ = '0.27.3'
__version__ = '0.27.4'
__all__ = (
aggregated,
analyze,
assert_max_length,
assert_non_nullable,
assert_nullable,
auto_delete_orphans,
batch_fetch,
coercion_listener,

View File

@@ -0,0 +1,99 @@
"""
The functions in this module can be used for testing that the constraints of
your models. Each assert function runs SQL UPDATEs that check for the existence
of given constraint. Consider the following model::
class User(Base):
__tablename__ = 'user'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String(200), nullable=True)
email = sa.Column(sa.String(255), nullable=False)
user = User(name='John Doe', email='john@example.com')
session.add(user)
session.commit()
We can easily test the constraints by assert_* functions::
from sqlalchemy_utils import (
assert_nullable,
assert_non_nullable,
assert_max_length
)
assert_nullable(user, 'name')
assert_non_nullable(user, 'email')
assert_max_length(user, 'name', 200)
# raises AssertionError because the max length of email is 255
assert_max_length(user, 'email', 300)
"""
import sqlalchemy as sa
from sqlalchemy.exc import DataError, IntegrityError
class raises(object):
def __init__(self, expected_exc):
self.expected_exc = expected_exc
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type != self.expected_exc:
return False
return True
def _update_field(obj, field, value):
session = sa.orm.object_session(obj)
table = sa.inspect(obj.__class__).columns[field].table
query = table.update().values(**{field: value})
session.execute(query)
session.flush()
def assert_nullable(obj, column):
"""
Assert that given column is nullable. This is checked by running an SQL
update that assigns given column as None.
:param obj: SQLAlchemy declarative model object
:param column: Name of the column
"""
try:
_update_field(obj, column, None)
except (IntegrityError) as e:
assert False, str(e)
def assert_non_nullable(obj, column):
"""
Assert that given column is not nullable. This is checked by running an SQL
update that assigns given column as None.
:param obj: SQLAlchemy declarative model object
:param column: Name of the column
"""
with raises(IntegrityError):
_update_field(obj, column, None)
def assert_max_length(obj, column, max_length):
"""
Assert that the given column is of given max length.
:param obj: SQLAlchemy declarative model object
:param column: Name of the column
"""
try:
_update_field(obj, column, u'a' * max_length)
except (DataError) as e:
assert False, str(e)
with raises(DataError):
_update_field(obj, column, u'a' * (max_length + 1))

74
tests/test_asserts.py Normal file
View File

@@ -0,0 +1,74 @@
import sqlalchemy as sa
import pytest
from sqlalchemy_utils import (
assert_nullable,
assert_non_nullable,
assert_max_length
)
from sqlalchemy_utils.asserts import raises
from tests import TestCase
class TestRaises(object):
def test_matching_exception(self):
with raises(Exception):
raise Exception()
assert True
def test_non_matchin_exception(self):
with pytest.raises(Exception):
with raises(ValueError):
raise Exception()
class AssertionTestCase(TestCase):
dns = 'postgres://postgres@localhost/sqlalchemy_utils_test'
def create_models(self):
class User(self.Base):
__tablename__ = 'user'
id = sa.Column(sa.Integer, primary_key=True)
name = sa.Column(sa.String(20))
age = sa.Column(sa.Integer, nullable=False)
email = sa.Column(sa.String(200), unique=True)
self.User = User
def setup_method(self, method):
TestCase.setup_method(self, method)
user = self.User(name='Someone', age=15)
self.session.add(user)
self.session.commit()
self.user = user
class TestAssertNonNullable(AssertionTestCase):
def test_non_nullable_column(self):
assert_non_nullable(self.user, 'age')
def test_nullable_column(self):
with raises(AssertionError):
assert_non_nullable(self.user, 'name')
class TestAssertNullable(AssertionTestCase):
def test_nullable_column(self):
assert_nullable(self.user, 'name')
def test_non_nullable_column(self):
with raises(AssertionError):
assert_nullable(self.user, 'age')
class TestAssertMaxLength(AssertionTestCase):
def test_with_max_length(self):
assert_max_length(self.user, 'name', 20)
def test_smaller_than_max_length(self):
with raises(AssertionError):
assert_max_length(self.user, 'name', 19)
def test_bigger_than_max_length(self):
with raises(AssertionError):
assert_max_length(self.user, 'name', 21)