API: use of pytest instead of unittest

This commit is contained in:
Sam 2018-04-09 22:09:58 +02:00
parent 2c5ad23f0c
commit 2d9d3056c2
10 changed files with 715 additions and 697 deletions

View File

@ -6,6 +6,10 @@ make-p:
# Launch all P targets in parallel and exit as soon as one exits. # Launch all P targets in parallel and exit as soon as one exits.
set -m; (for p in $(P); do ($(MAKE) $$p || kill 0)& done; wait) set -m; (for p in $(P); do ($(MAKE) $$p || kill 0)& done; wait)
clean-install: clean
rm -fr $(NODE_MODULES)
rm -fr $(VENV)
init-db: init-db:
$(FLASK) drop_db $(FLASK) drop_db
$(FLASK) db upgrade --directory $(MIGRATIONS) $(FLASK) db upgrade --directory $(MIGRATIONS)

View File

@ -5,49 +5,53 @@ from flask_bcrypt import Bcrypt
from flask_migrate import Migrate from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() db = SQLAlchemy()
bcrypt = Bcrypt() bcrypt = Bcrypt()
migrate = Migrate() migrate = Migrate()
appLog = logging.getLogger('mpwo_api') appLog = logging.getLogger('mpwo_api')
# instantiate the app
app = Flask(__name__)
# set config def create_app():
with app.app_context(): # instantiate the app
app.config.from_object('mpwo_api.config.DevelopmentConfig') app = Flask(__name__)
# set up extensions # set config
db.init_app(app) with app.app_context():
bcrypt.init_app(app) app.config.from_object('mpwo_api.config.DevelopmentConfig')
migrate.init_app(app, db)
from .users.auth import auth_blueprint # noqa # set up extensions
from .users.users import users_blueprint # noqa db.init_app(app)
from .activities.activities import activities_blueprint # noqa bcrypt.init_app(app)
migrate.init_app(app, db)
app.register_blueprint(users_blueprint, url_prefix='/api') from .users.auth import auth_blueprint # noqa
app.register_blueprint(auth_blueprint, url_prefix='/api') from .users.users import users_blueprint # noqa
app.register_blueprint(activities_blueprint, url_prefix='/api') from .activities.activities import activities_blueprint # noqa
if app.debug: app.register_blueprint(users_blueprint, url_prefix='/api')
logging.getLogger('sqlalchemy').setLevel(logging.WARNING) app.register_blueprint(auth_blueprint, url_prefix='/api')
logging.getLogger('sqlalchemy' app.register_blueprint(activities_blueprint, url_prefix='/api')
).handlers = logging.getLogger('werkzeug').handlers
logging.getLogger('sqlalchemy.orm').setLevel(logging.WARNING)
logging.getLogger('flake8').propagate = False
appLog.setLevel(logging.DEBUG)
if app.debug: if app.debug:
# Enable CORS logging.getLogger('sqlalchemy').setLevel(logging.WARNING)
@app.after_request logging.getLogger('sqlalchemy'
def after_request(response): ).handlers = logging.getLogger('werkzeug').handlers
response.headers.add('Access-Control-Allow-Origin', '*') logging.getLogger('sqlalchemy.orm').setLevel(logging.WARNING)
response.headers.add( logging.getLogger('flake8').propagate = False
'Access-Control-Allow-Headers', 'Content-Type,Authorization' appLog.setLevel(logging.DEBUG)
)
response.headers.add( if app.debug:
'Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH,OPTIONS' # Enable CORS
) @app.after_request
return response def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add(
'Access-Control-Allow-Headers', 'Content-Type,Authorization'
)
response.headers.add(
'Access-Control-Allow-Methods',
'GET,PUT,POST,DELETE,PATCH,OPTIONS'
)
return response
return app

View File

@ -31,6 +31,7 @@ class DevelopmentConfig(BaseConfig):
class TestingConfig(BaseConfig): class TestingConfig(BaseConfig):
"""Development configuration""" """Development configuration"""
DEBUG = True DEBUG = True
TESTING = True
SQLALCHEMY_DATABASE_URI = \ SQLALCHEMY_DATABASE_URI = \
os.environ.get('DATABASE_TEST_URL') os.environ.get('DATABASE_TEST_URL')
SECRET_KEY = 'test key' SECRET_KEY = 'test key'

View File

@ -1,16 +0,0 @@
from flask_testing import TestCase
from mpwo_api import app, db
class BaseTestCase(TestCase):
def create_app(self):
app.config.from_object('mpwo_api.config.TestingConfig')
return app
def setUp(self):
db.create_all()
db.session.commit()
def tearDown(self):
db.session.remove()
db.drop_all()

View File

@ -0,0 +1,14 @@
import pytest
from mpwo_api import create_app, db
@pytest.fixture
def app():
app = create_app()
app.config.from_object('mpwo_api.config.TestingConfig')
with app.app_context():
db.create_all()
yield app
db.session.remove()
db.drop_all()
return app

View File

@ -1,94 +1,87 @@
import datetime import datetime
import json import json
from mpwo_api.tests.base import BaseTestCase
from mpwo_api.tests.utils import add_activity, add_sport, add_user from mpwo_api.tests.utils import add_activity, add_sport, add_user
class TestActivitiesService(BaseTestCase): def test_get_all_sports(app):
"""Tests for Activities.""" add_user('test', 'test@test.com', '12345678')
add_sport('cycling')
add_sport('running')
def test_get_all_sports(self): client = app.test_client()
add_user('test', 'test@test.com', '12345678') resp_login = client.post(
add_sport('cycling') '/api/auth/login',
add_sport('running') data=json.dumps(dict(
email='test@test.com',
password='12345678'
)),
content_type='application/json'
)
response = client.get(
'/api/sports',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
with self.client: assert response.status_code == 200
resp_login = self.client.post( assert 'success' in data['status']
'/api/auth/login',
data=json.dumps(dict(
email='test@test.com',
password='12345678'
)),
content_type='application/json'
)
response = self.client.get(
'/api/sports',
headers=dict(
Authorization='Bearer ' + json.loads(
resp_login.data.decode()
)['auth_token']
)
)
data = json.loads(response.data.decode())
self.assertEqual(response.status_code, 200) assert len(data['data']['sports']) == 2
self.assertIn('success', data['status']) assert 'cycling' in data['data']['sports'][0]['label']
assert 'running' in data['data']['sports'][1]['label']
self.assertEqual(len(data['data']['sports']), 2)
self.assertIn('cycling', data['data']['sports'][0]['label'])
self.assertIn('running', data['data']['sports'][1]['label'])
def test_get_all_activities(self): def test_get_all_activities(app):
add_user('test', 'test@test.com', '12345678') add_user('test', 'test@test.com', '12345678')
add_user('toto', 'toto@toto.com', '12345678') add_user('toto', 'toto@toto.com', '12345678')
add_sport('cycling') add_sport('cycling')
add_sport('running') add_sport('running')
add_activity( add_activity(
1, 1,
2, 2,
datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'), datetime.datetime.strptime('01/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=1024)) datetime.timedelta(seconds=1024))
add_activity( add_activity(
2, 2,
1, 1,
datetime.datetime.strptime('23/01/2018', '%d/%m/%Y'), datetime.datetime.strptime('23/01/2018', '%d/%m/%Y'),
datetime.timedelta(seconds=3600)) datetime.timedelta(seconds=3600))
with self.client: client = app.test_client()
resp_login = self.client.post( resp_login = client.post(
'/api/auth/login', '/api/auth/login',
data=json.dumps(dict( data=json.dumps(dict(
email='test@test.com', email='test@test.com',
password='12345678' password='12345678'
)), )),
content_type='application/json' content_type='application/json'
) )
response = self.client.get( response = client.get(
'/api/activities', '/api/activities',
headers=dict( headers=dict(
Authorization='Bearer ' + json.loads( Authorization='Bearer ' + json.loads(
resp_login.data.decode() resp_login.data.decode()
)['auth_token'] )['auth_token']
) )
) )
data = json.loads(response.data.decode()) data = json.loads(response.data.decode())
self.assertEqual(response.status_code, 200) assert response.status_code == 200
self.assertIn('success', data['status']) assert 'success' in data['status']
self.assertEqual(len(data['data']['activities']), 2) assert len(data['data']['activities']) == 2
self.assertTrue('creation_date' in data['data']['activities'][0]) assert 'creation_date' in data['data']['activities'][0]
self.assertTrue('creation_date' in data['data']['activities'][1]) assert 'creation_date' in data['data']['activities'][1]
self.assertEqual('Tue, 23 Jan 2018 00:00:00 GMT', assert 'Tue, 23 Jan 2018 00:00:00 GMT' == data['data']['activities'][0]['activity_date'] # noqa
data['data']['activities'][0][ assert 'Mon, 01 Jan 2018 00:00:00 GMT' == data['data']['activities'][1]['activity_date'] # noqa
'activity_date']) assert 'creation_date' in data['data']['activities'][1]
self.assertEqual('Mon, 01 Jan 2018 00:00:00 GMT', assert 2 == data['data']['activities'][0]['user_id']
data['data']['activities'][1][ assert 1 == data['data']['activities'][1]['user_id']
'activity_date']) assert 1 == data['data']['activities'][0]['sport_id']
self.assertTrue('creation_date' in data['data']['activities'][1]) assert 2 == data['data']['activities'][1]['sport_id']
self.assertEqual(2, data['data']['activities'][0]['user_id']) assert 3600 == data['data']['activities'][0]['duration']
self.assertEqual(1, data['data']['activities'][1]['user_id']) assert 1024 == data['data']['activities'][1]['duration']
self.assertEqual(1, data['data']['activities'][0]['sport_id'])
self.assertEqual(2, data['data']['activities'][1]['sport_id'])
self.assertEqual(3600, data['data']['activities'][0]['duration'])
self.assertEqual(1024, data['data']['activities'][1]['duration'])

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
import os
def test_development_config(app):
app.config.from_object('mpwo_api.config.DevelopmentConfig')
assert app.config['DEBUG']
assert not app.config['TESTING']
assert app.config['SQLALCHEMY_DATABASE_URI'] == os.environ.get(
'DATABASE_URL')
def test_testing_config(app):
app.config.from_object('mpwo_api.config.TestingConfig')
assert app.config['DEBUG']
assert app.config['TESTING']
assert not app.config['PRESERVE_CONTEXT_ON_EXCEPTION']
assert app.config['SQLALCHEMY_DATABASE_URI'] == os.environ.get(
'DATABASE_TEST_URL')

View File

@ -1,83 +1,87 @@
import json import json
from mpwo_api.tests.base import BaseTestCase
from mpwo_api.tests.utils import add_user from mpwo_api.tests.utils import add_user
from mpwo_api.users.models import User from mpwo_api.users.models import User
class TestUserService(BaseTestCase): def test_ping(app):
"""Tests for the Users Service.""" """ => Ensure the /ping route behaves correctly."""
client = app.test_client()
response = client.get('/api/ping')
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'pong' in data['message']
assert 'success' in data['status']
def test_users(self):
""" => Ensure the /ping route behaves correctly."""
response = self.client.get('/api/ping')
data = json.loads(response.data.decode())
self.assertEqual(response.status_code, 200)
self.assertIn('pong!', data['message'])
self.assertIn('success', data['status'])
def test_single_user(self): def test_single_user(app):
"""=> Get single user details""" """=> Get single user details"""
user = add_user('test', 'test@test.com', 'test') user = add_user('test', 'test@test.com', 'test')
client = app.test_client()
with self.client: response = client.get(f'/api/users/{user.id}')
response = self.client.get(f'/api/users/{user.id}') data = json.loads(response.data.decode())
data = json.loads(response.data.decode())
self.assertEqual(response.status_code, 200) assert response.status_code == 200
self.assertIn('success', data['status']) assert 'success' in data['status']
self.assertTrue('created_at' in data['data']) assert 'created_at' in data['data']
self.assertIn('test', data['data']['username']) assert 'test' in data['data']['username']
self.assertIn('test@test.com', data['data']['email']) assert 'test@test.com' in data['data']['email']
def test_single_user_no_id(self):
"""=> Ensure error is thrown if an id is not provided."""
with self.client:
response = self.client.get(f'/api/users/blah')
data = json.loads(response.data.decode())
self.assertEqual(response.status_code, 404) def test_single_user_no_id(app):
self.assertIn('fail', data['status']) """=> Ensure error is thrown if an id is not provided."""
self.assertIn('User does not exist', data['message']) client = app.test_client()
response = client.get(f'/api/users/blah')
data = json.loads(response.data.decode())
def test_single_user_wrong_id(self): assert response.status_code == 404
"""=> Ensure error is thrown if the id does not exist.""" assert 'fail' in data['status']
with self.client: assert 'User does not exist' in data['message']
response = self.client.get(f'/api/users/99999999999')
data = json.loads(response.data.decode())
self.assertEqual(response.status_code, 404)
self.assertIn('fail', data['status'])
self.assertIn('User does not exist', data['message'])
def test_users_list(self): def test_single_user_wrong_id(app):
"""=> Ensure get single user behaves correctly.""" """=> Ensure error is thrown if the id does not exist."""
add_user('test', 'test@test.com', 'test') client = app.test_client()
add_user('toto', 'toto@toto.com', 'toto') response = client.get(f'/api/users/99999999999')
with self.client: data = json.loads(response.data.decode())
response = self.client.get('/api/users')
data = json.loads(response.data.decode())
self.assertEqual(response.status_code, 200) assert response.status_code == 404
self.assertIn('success', data['status']) assert 'fail' in data['status']
assert 'User does not exist' in data['message']
self.assertEqual(len(data['data']['users']), 2)
self.assertTrue('created_at' in data['data']['users'][0])
self.assertTrue('created_at' in data['data']['users'][1])
self.assertIn('test', data['data']['users'][0]['username'])
self.assertIn('toto', data['data']['users'][1]['username'])
self.assertIn('test@test.com', data['data']['users'][0]['email'])
self.assertIn('toto@toto.com', data['data']['users'][1]['email'])
def test_encode_auth_token(self): def test_users_list(app):
"""=> Ensure correct auth token generation""" """=> Ensure get single user behaves correctly."""
user = add_user('test', 'test@test.com', 'test') add_user('test', 'test@test.com', 'test')
auth_token = user.encode_auth_token(user.id) add_user('toto', 'toto@toto.com', 'toto')
self.assertTrue(isinstance(auth_token, bytes))
def test_decode_auth_token(self): client = app.test_client()
user = add_user('test', 'test@test.com', 'test') response = client.get('/api/users')
auth_token = user.encode_auth_token(user.id) data = json.loads(response.data.decode())
self.assertTrue(isinstance(auth_token, bytes))
self.assertTrue(User.decode_auth_token(auth_token), user.id) assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['users']) == 2
assert 'created_at' in data['data']['users'][0]
assert 'created_at' in data['data']['users'][1]
assert 'test' in data['data']['users'][0]['username']
assert 'toto' in data['data']['users'][1]['username']
assert 'test@test.com' in data['data']['users'][0]['email']
assert 'toto@toto.com' in data['data']['users'][1]['email']
def test_encode_auth_token(app):
"""=> Ensure correct auth token generation"""
user = add_user('test', 'test@test.com', 'test')
auth_token = user.encode_auth_token(user.id)
assert isinstance(auth_token, bytes)
def test_decode_auth_token(app):
user = add_user('test', 'test@test.com', 'test')
auth_token = user.encode_auth_token(user.id)
assert isinstance(auth_token, bytes)
assert User.decode_auth_token(auth_token) == user.id

View File

@ -1,9 +1,9 @@
import unittest from mpwo_api import create_app, db
from mpwo_api import app, db
from mpwo_api.activities.models import Sport from mpwo_api.activities.models import Sport
from mpwo_api.users.models import User from mpwo_api.users.models import User
app = create_app()
@app.cli.command() @app.cli.command()
def drop_db(): def drop_db():
@ -31,21 +31,5 @@ def init_data():
print('Initial data stored in database.') print('Initial data stored in database.')
def run_test(test_path='mpwo_api/tests'):
"""Runs the tests without code coverage."""
tests = unittest.TestLoader().discover(
test_path, pattern='test*.py')
result = unittest.TextTestRunner(verbosity=2).run(tests)
if result.wasSuccessful():
return 0
return 1
@app.cli.command()
def test():
"""Runs the tests without code coverage."""
run_test()
if __name__ == '__main__': if __name__ == '__main__':
app.run() app.run()