Skip to content

Commit

Permalink
Removes dependencies on nose.
Browse files Browse the repository at this point in the history
Well, not entirely. The `setup.py` module still specifies that the test
suite is the nose test collector and that the tests require
nose. However, this commit should allow the tests to run both with and
without nose (for example, with just `python setup.py test`). This is
intended to future-proof the code, since nose is no longer actively
maintained.
  • Loading branch information
jfinkels committed Apr 6, 2016
1 parent eae04ce commit 4b3cc1b
Show file tree
Hide file tree
Showing 20 changed files with 170 additions and 216 deletions.
86 changes: 17 additions & 69 deletions tests/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
from json import JSONEncoder
import sys
import types
from unittest import skipUnless as skip_unless
from unittest import TestCase
import uuid

from flask import Flask
Expand All @@ -29,7 +31,6 @@
has_flask_sqlalchemy = False
else:
has_flask_sqlalchemy = True
from nose import SkipTest
from sqlalchemy import create_engine
from sqlalchemy import event
from sqlalchemy.dialects.postgresql import UUID
Expand Down Expand Up @@ -71,60 +72,6 @@ def isclass(obj):
return isinstance(obj, CLASS_TYPES)


def skip_unless(condition, reason=None):
"""Decorator that skips `test` unless `condition` is ``True``.
This is a replacement for :func:`unittest.skipUnless` that works with
``nose``. The argument ``reason`` is a string describing why the test was
skipped.
This decorator can be applied to functions, methods, or classes.
"""

def decorated(test):
"""Returns a decorated version of ``test``, as described in the
wrapper defined within.
"""
message = 'Skipped {0}: {1}'.format(test.__name__, reason)

# HACK-ish: If the test is actually a test class, override the
# setup method so that the only thing it does is raise
# `SkipTest`. Thus whenever setup() is called, the test that
# would have been run is skipped.
if isclass(test):
if not condition:
def new_setup(self):
raise SkipTest(message)

test.setup = new_setup
return test

@wraps(test)
def inner(*args, **kw):
"""Checks that ``condition`` is ``True`` before executing
``test(*args, **kw)``.
"""
if not condition:
raise SkipTest(message)
return test(*args, **kw)

return inner

return decorated


def skip(reason=None):
"""Unconditionally skip a test.
This is a convenience function for ``skip_unless(False, reason)``.
"""
return skip_unless(False, reason)


def parse_version(version_string):
"""Parses the Flask-SQLAlchemy version string into a pair of
integers.
Expand Down Expand Up @@ -270,15 +217,15 @@ def default(self, obj):
return super(BetterJSONEncoder, self).default(obj)


class FlaskTestBase(object):
class FlaskTestBase(TestCase):
"""Base class for tests which use a Flask application.
The Flask test client can be accessed at ``self.app``. The Flask
application itself is accessible at ``self.flaskapp``.
"""

def setup(self):
def setUp(self):
"""Creates the Flask application and the APIManager."""
# create the Flask application
app = Flask(__name__)
Expand Down Expand Up @@ -316,20 +263,21 @@ def database_uri(self):
return 'sqlite://'


@skip_unless(has_flask_sqlalchemy, 'Flask-SQLAlchemy not found')
class FlaskSQLAlchemyTestBase(FlaskTestBase, DatabaseMixin):
"""Base class for tests that use Flask-SQLAlchemy (instead of plain
old SQLAlchemy).
If Flask-SQLAlchemy is not installed, the :meth:`.setup` method will
If Flask-SQLAlchemy is not installed, the :meth:`.setUp` method will
raise :exc:`nose.SkipTest`, so that each test method will be
skipped individually.
"""

def setup(self):
super(FlaskSQLAlchemyTestBase, self).setup()
if not has_flask_sqlalchemy:
raise SkipTest('Flask-SQLAlchemy not found.')
def setUp(self):
super(FlaskSQLAlchemyTestBase, self).setUp()
# if not has_flask_sqlalchemy:
# raise SkipTest('Flask-SQLAlchemy not found.')
self.flaskapp.config['SQLALCHEMY_DATABASE_URI'] = self.database_uri()
# This is to avoid a warning in earlier versions of
# Flask-SQLAlchemy.
Expand All @@ -339,7 +287,7 @@ def setup(self):
self.db = SQLAlchemy(self.flaskapp)
self.session = self.db.session

def teardown(self):
def tearDown(self):
"""Drops all tables and unregisters Flask-SQLAlchemy session
signals.
Expand All @@ -351,7 +299,7 @@ def teardown(self):
class SQLAlchemyTestBase(FlaskTestBase, DatabaseMixin):
"""Base class for tests that use a SQLAlchemy database.
The :meth:`setup` method does the necessary SQLAlchemy
The :meth:`setUp` method does the necessary SQLAlchemy
initialization, and the subclasses should populate the database with
models and then create the database (by calling
``self.Base.metadata.create_all()``).
Expand All @@ -362,20 +310,20 @@ class SQLAlchemyTestBase(FlaskTestBase, DatabaseMixin):
"""

def setup(self):
def setUp(self):
"""Initializes the components necessary for models in a SQLAlchemy
database.
"""
super(SQLAlchemyTestBase, self).setup()
super(SQLAlchemyTestBase, self).setUp()
engine = create_engine(self.database_uri(), convert_unicode=True)
self.Session = sessionmaker(autocommit=False, autoflush=False,
bind=engine)
self.session = scoped_session(self.Session)
self.Base = declarative_base()
self.Base.metadata.bind = engine

def teardown(self):
def tearDown(self):
"""Drops all tables from the temporary database."""
self.session.remove()
self.Base.metadata.drop_all()
Expand All @@ -396,11 +344,11 @@ class ManagerTestBase(SQLAlchemyTestBase):
"""

def setup(self):
def setUp(self):
"""Initializes an instance of
:class:`~flask.ext.restless.APIManager` with a SQLAlchemy
session.
"""
super(ManagerTestBase, self).setup()
super(ManagerTestBase, self).setUp()
self.manager = APIManager(self.flaskapp, session=self.session)
15 changes: 8 additions & 7 deletions tests/test_bulk.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@
# License version 3 and under the 3-clause BSD license. For more
# information, see LICENSE.AGPL and LICENSE.BSD.
"""Unit tests for the JSON API Bulk extension."""
from unittest import skip

from sqlalchemy import Column
from sqlalchemy import Integer

from .helpers import dumps
from .helpers import loads
from .helpers import ManagerTestBase
from .helpers import skip


@skip('Not yet implemented')
Expand All @@ -30,8 +31,8 @@ class TestCreating(ManagerTestBase):
"""

def setup(self):
super(TestCreating, self).setup()
def setUp(self):
super(TestCreating, self).setUp()

class Person(self.Base):
__tablename__ = 'person'
Expand Down Expand Up @@ -72,8 +73,8 @@ class TestUpdating(ManagerTestBase):
"""

def setup(self):
super(TestUpdating, self).setup()
def setUp(self):
super(TestUpdating, self).setUp()

class Person(self.Base):
__tablename__ = 'person'
Expand Down Expand Up @@ -229,8 +230,8 @@ class TestDeleting(ManagerTestBase):
"""

def setup(self):
super(TestDeleting, self).setup()
def setUp(self):
super(TestDeleting, self).setUp()

class Person(self.Base):
__tablename__ = 'person'
Expand Down
18 changes: 9 additions & 9 deletions tests/test_creating.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"""
from __future__ import division
from datetime import datetime
from unittest import skip

import dateutil
from sqlalchemy import Column
Expand Down Expand Up @@ -50,7 +51,6 @@
from .helpers import ManagerTestBase
from .helpers import MSIE8_UA
from .helpers import MSIE9_UA
from .helpers import skip


def raise_s_exception(instance, *args, **kw):
Expand All @@ -77,14 +77,14 @@ def raise_d_exception(*args, **kw):
class TestCreating(ManagerTestBase):
"""Tests for creating resources."""

def setup(self):
def setUp(self):
"""Creates the database, the :class:`~flask.Flask` object, the
:class:`~flask_restless.manager.APIManager` for that application, and
creates the ReSTful API endpoints for the :class:`TestSupport.Person`
and :class:`TestSupport.Article` models.
"""
super(TestCreating, self).setup()
super(TestCreating, self).setUp()

class Article(self.Base):
__tablename__ = 'article'
Expand Down Expand Up @@ -835,8 +835,8 @@ def test_to_many_relationship_conflicting_type(self):
class TestProcessors(ManagerTestBase):
"""Tests for pre- and postprocessors."""

def setup(self):
super(TestProcessors, self).setup()
def setUp(self):
super(TestProcessors, self).setUp()

class Person(self.Base):
__tablename__ = 'person'
Expand Down Expand Up @@ -889,14 +889,14 @@ class TestAssociationProxy(ManagerTestBase):
"""

def setup(self):
def setUp(self):
"""Creates the database, the :class:`~flask.Flask` object, the
:class:`~flask.ext.restless.manager.APIManager` for that application,
and creates the ReSTful API endpoints for the models used in the test
methods.
"""
super(TestAssociationProxy, self).setup()
super(TestAssociationProxy, self).setUp()

class Article(self.Base):
__tablename__ = 'article'
Expand Down Expand Up @@ -995,9 +995,9 @@ class TestFlaskSQLAlchemy(FlaskSQLAlchemyTestBase):
"""

def setup(self):
def setUp(self):
"""Creates the Flask-SQLAlchemy database and models."""
super(TestFlaskSQLAlchemy, self).setup()
super(TestFlaskSQLAlchemy, self).setUp()

class Person(self.db.Model):
id = self.db.Column(self.db.Integer, primary_key=True)
Expand Down
15 changes: 8 additions & 7 deletions tests/test_deleting.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
specification.
"""
from unittest import skip

from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
Expand All @@ -33,20 +35,19 @@
from .helpers import ManagerTestBase
from .helpers import MSIE8_UA
from .helpers import MSIE9_UA
from .helpers import skip


class TestDeleting(ManagerTestBase):
"""Tests for deleting resources."""

def setup(self):
def setUp(self):
"""Creates the database, the :class:`~flask.Flask` object, the
:class:`~flask_restless.manager.APIManager` for that application, and
creates the ReSTful API endpoints for the :class:`TestSupport.Person`
and :class:`TestSupport.Article` models.
"""
super(TestDeleting, self).setup()
super(TestDeleting, self).setUp()

class Article(self.Base):
__tablename__ = 'article'
Expand Down Expand Up @@ -173,8 +174,8 @@ def test_related_resource_url(self):
class TestProcessors(ManagerTestBase):
"""Tests for pre- and postprocessors."""

def setup(self):
super(TestProcessors, self).setup()
def setUp(self):
super(TestProcessors, self).setUp()

class Person(self.Base):
__tablename__ = 'person'
Expand Down Expand Up @@ -272,9 +273,9 @@ class TestFlaskSQLAlchemy(FlaskSQLAlchemyTestBase):
"""

def setup(self):
def setUp(self):
"""Creates the Flask-SQLAlchemy database and models."""
super(TestFlaskSQLAlchemy, self).setup()
super(TestFlaskSQLAlchemy, self).setUp()

class Person(self.db.Model):
id = self.db.Column(self.db.Integer, primary_key=True)
Expand Down
Loading

0 comments on commit 4b3cc1b

Please sign in to comment.