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
	 Konsta Vesterinen
					Konsta Vesterinen