Add assert_* functions
This commit is contained in:
@@ -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)
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@@ -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
20
docs/testing.rst
Normal 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
|
@@ -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,
|
||||
|
99
sqlalchemy_utils/asserts.py
Normal file
99
sqlalchemy_utils/asserts.py
Normal 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
74
tests/test_asserts.py
Normal 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)
|
Reference in New Issue
Block a user