From c359c401e74f26c2b73403f7a756ccb93b571f32 Mon Sep 17 00:00:00 2001 From: Pat Ferate Date: Tue, 26 Jul 2016 09:47:22 -0700 Subject: [PATCH] Migrate test runner to py.test Migrating test runner from `unittest2`/`nose` to `pytest`. The pytest runner is also compatible with both unittest and nose tests. Some of the benefits of PyTest include: * using plain asserts * function-based fixtures instead of setUp and tearDown * no strange camelCase methods --- .gitignore | 1 + tests/__init__.py | 22 ---------- tests/conftest.py | 46 ++++++++++++++++++++ tests/contrib/test_appengine.py | 4 -- tests/test_jwt.py | 12 ++++++ tests/test_service_account.py | 6 +++ tox.ini | 76 ++++++++++++++------------------- 7 files changed, 97 insertions(+), 70 deletions(-) create mode 100644 tests/conftest.py diff --git a/.gitignore b/.gitignore index 89c1121..0bc898c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ docs/_build # Test files .tox/ +.cache/ # Django test database db.sqlite3 diff --git a/tests/__init__.py b/tests/__init__.py index 5e20108..e69de29 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,22 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Test package set-up.""" - -from oauth2client import _helpers - -__author__ = 'afshar@google.com (Ali Afshar)' - - -def setup_package(): - """Run on testing package.""" - _helpers.positional_parameters_enforcement = _helpers.POSITIONAL_EXCEPTION diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..5d53edd --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,46 @@ +# Copyright 2016 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Common testing tools for OAuth2Client tests.""" + +import sys + +from six.moves import reload_module + +from oauth2client import util + + +def set_up_gae_environment(gae_sdk_path): + """Set up appengine SDK third-party imports.""" + if 'google' in sys.modules: + # Some packages, such as protobuf, clobber the google + # namespace package. This prevents that. + reload_module(sys.modules['google']) + + # This sets up google-provided libraries. + sys.path.insert(0, gae_sdk_path) + import dev_appserver + dev_appserver.fix_sys_path() + + # Fixes timezone and other os-level items. + import google.appengine.tools.os_compat # noqa: unused import + + +def pytest_configure(config): + """Pytest hook function for setting up test session.""" + # Set up Google SDK modules unless specified not to + if not config.option.no_gae: + set_up_gae_environment(config.option.sdk_path) + # Default of POSITIONAL_WARNING is too verbose for testing + util.positional_parameters_enforcement = util.POSITIONAL_EXCEPTION diff --git a/tests/contrib/test_appengine.py b/tests/contrib/test_appengine.py index 7e6050e..b6d2dad 100644 --- a/tests/contrib/test_appengine.py +++ b/tests/contrib/test_appengine.py @@ -18,10 +18,6 @@ import os import tempfile import time -import dev_appserver - -dev_appserver.fix_sys_path() - from google.appengine.api import apiproxy_stub from google.appengine.api import apiproxy_stub_map from google.appengine.api import app_identity diff --git a/tests/test_jwt.py b/tests/test_jwt.py index ecc58e8..67fc9c1 100644 --- a/tests/test_jwt.py +++ b/tests/test_jwt.py @@ -235,9 +235,13 @@ class PEMCryptTestsOpenSSL(CryptTests): class SignedJwtAssertionCredentialsTests(unittest2.TestCase): def setUp(self): + self.orig_signer = crypt.Signer self.format_ = 'p12' crypt.Signer = crypt.OpenSSLSigner + def tearDown(self): + crypt.Signer = self.orig_signer + def _make_credentials(self): private_key = datafile('privatekey.' + self.format_) signer = crypt.Signer.from_string(private_key) @@ -310,17 +314,25 @@ class PEMSignedJwtAssertionCredentialsOpenSSLTests( SignedJwtAssertionCredentialsTests): def setUp(self): + self.orig_signer = crypt.Signer self.format_ = 'pem' crypt.Signer = crypt.OpenSSLSigner + def tearDown(self): + crypt.Signer = self.orig_signer + class PEMSignedJwtAssertionCredentialsPyCryptoTests( SignedJwtAssertionCredentialsTests): def setUp(self): + self.orig_signer = crypt.Signer self.format_ = 'pem' crypt.Signer = crypt.PyCryptoSigner + def tearDown(self): + crypt.Signer = self.orig_signer + class TestHasOpenSSLFlag(unittest2.TestCase): diff --git a/tests/test_service_account.py b/tests/test_service_account.py index 755a79b..b5ae482 100644 --- a/tests/test_service_account.py +++ b/tests/test_service_account.py @@ -45,6 +45,8 @@ def datafile(filename): class ServiceAccountCredentialsTests(unittest2.TestCase): def setUp(self): + self.orig_signer = crypt.Signer + self.orig_verifier = crypt.Verifier self.client_id = '123' self.service_account_email = 'dummy@google.com' self.private_key_id = 'ABCDEF' @@ -58,6 +60,10 @@ class ServiceAccountCredentialsTests(unittest2.TestCase): client_id=self.client_id, ) + def tearDown(self): + crypt.Signer = self.orig_signer + crypt.Verifier = self.orig_verifier + def test__to_json_override(self): signer = object() creds = service_account.ServiceAccountCredentials( diff --git a/tox.ini b/tox.ini index 31a638e..06ba055 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,8 @@ basedeps = mock>=1.3.0 cryptography>=1.0 pyopenssl>=0.14 webtest - nose + pytest + pytest-beds flask unittest2 sqlalchemy @@ -18,60 +19,54 @@ deps = {[testenv]basedeps} setenv = pypy: with_gmp=no DJANGO_SETTINGS_MODULE=tests.contrib.django_util.settings -commands = nosetests --ignore-files=test_appengine\.py --ignore-files=test__appengine_ndb\.py {posargs} +commands = + py.test \ + --no-gae \ + --ignore=tests/contrib/test_appengine.py \ + --ignore=tests/contrib/test__appengine_ndb.py \ + {posargs} [coverbase] basepython = python2.7 commands = - nosetests \ - --with-coverage \ - --cover-package=oauth2client \ - --cover-package=tests \ - --cover-erase \ - --cover-tests \ - --cover-branches \ - --ignore-files=test_appengine\.py \ - --ignore-files=test__appengine_ndb\.py - nosetests \ - --with-coverage \ - --cover-package=oauth2client.contrib.appengine \ - --cover-package=oauth2client.contrib._appengine_ndb \ - --cover-package=tests.contrib.test_appengine \ - --cover-package=tests.contrib.test__appengine_ndb \ - --with-gae \ - --cover-tests \ - --cover-branches \ - --gae-application=tests/data \ - --gae-lib-root={env:GAE_PYTHONPATH:google_appengine} \ - --logging-level=INFO \ + py.test \ + --no-gae \ + --cov=oauth2client \ + --cov=tests \ + --ignore=tests/contrib/test_appengine.py \ + --ignore=tests/contrib/test__appengine_ndb.py + py.test \ + --cov=oauth2client \ + --cov=tests \ + --cov-append \ + --sdk-path={env:GAE_PYTHONPATH:google_appengine} \ tests/contrib/test_appengine.py \ tests/contrib/test__appengine_ndb.py deps = {[testenv]deps} coverage - nosegae + pytest-cov [testenv:py33] basepython = python3.3 commands = - nosetests \ - --ignore-files=test_appengine\.py \ - --ignore-files=test__appengine_ndb\.py \ - --ignore-files=test_django_orm\.py \ - --ignore-files=test_django_settings\.py \ - --ignore-files=test_django_util\.py \ - --exclude-dir=oauth2client/contrib/django_util \ - --exclude-dir=tests/contrib/django_util \ + py.test \ + --no-gae \ + --ignore=tests/contrib/test_appengine.py \ + --ignore=tests/contrib/test__appengine_ndb.py \ + --ignore=tests/contrib/test_django_orm.py \ + --ignore=tests/contrib/test_django_settings.py \ + --ignore=oauth2client/contrib/django_util \ + --ignore=tests/contrib/django_util \ {posargs} deps = {[testenv]basedeps} keyring - nose-exclude [testenv:cover] basepython = {[coverbase]basepython} commands = {[coverbase]commands} - coverage report --show-missing --cover-min-percentage=100 + coverage report --show-missing --fail-under=100 deps = {[coverbase]deps} @@ -100,13 +95,9 @@ commands = {toxinidir}/scripts/build_docs.sh [testenv:gae] basepython = python2.7 deps = {[testenv]basedeps} - nosegae commands = - nosetests \ - --with-gae \ - --gae-lib-root={env:GAE_PYTHONPATH:google_appengine} \ - --gae-application=tests/data \ - --logging-level=INFO \ + py.test \ + --sdk-path={env:GAE_PYTHONPATH:google_appengine} \ tests/contrib/test_appengine.py \ tests/contrib/test__appengine_ndb.py @@ -153,11 +144,8 @@ exclude = .tox,.git,./*.egg,build, application-import-names = oauth2client putty-ignore = # E402 module level import not at top of file - # These files have needed configurations defined before import + # This file has needed configurations defined before import docs/conf.py : E402 - tests/contrib/test_appengine.py : E402 - # Additionally, ignore E100 (imports in wrong order) for Django configuration - tests/contrib/test_django_orm.py : E402,I100 # E501 line too long # Ignore lines over 80 chars that include "http:" or "https:" /http:/ : E501