done: Test Coverage
This commit is contained in:
parent
5f1621ffd1
commit
fe35e21da6
7 changed files with 261 additions and 0 deletions
|
|
@ -9,3 +9,10 @@ dependencies = [
|
|||
[build-system]
|
||||
requires = ["flit_core<4"]
|
||||
build-backend = "flit_core.buildapi"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
|
||||
[tool.coverage.run]
|
||||
branch = true
|
||||
source = ["flaskr"]
|
||||
|
|
|
|||
57
tests/conftest.py
Normal file
57
tests/conftest.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import os
|
||||
import tempfile
|
||||
|
||||
import pytest
|
||||
from flaskr import create_app
|
||||
from flaskr.db import get_db, init_db
|
||||
|
||||
with open(os.path.join(os.path.dirname(__file__), 'data.sql'), 'rb') as f:
|
||||
_data_sql = f.read().decode('utf8')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app():
|
||||
db_fd, db_path = tempfile.mkstemp()
|
||||
|
||||
app = create_app({
|
||||
'TESTING': True,
|
||||
'DATABASE': db_path,
|
||||
})
|
||||
|
||||
with app.app_context():
|
||||
init_db()
|
||||
get_db().executescript(_data_sql)
|
||||
|
||||
yield app
|
||||
|
||||
os.close(db_fd)
|
||||
os.unlink(db_path)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client(app):
|
||||
return app.test_client()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def runner(app):
|
||||
return app.test_cli_runner()
|
||||
|
||||
|
||||
class AuthActions(object):
|
||||
def __init__(self, client):
|
||||
self._client = client
|
||||
|
||||
def login(self, username='test', password='test'):
|
||||
return self._client.post(
|
||||
'/auth/login',
|
||||
data={'username': username, 'password': password}
|
||||
)
|
||||
|
||||
def logout(self):
|
||||
return self._client.get('/auth/logout')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def auth(client):
|
||||
return AuthActions(client)
|
||||
8
tests/data.sql
Normal file
8
tests/data.sql
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
INSERT INTO user (username, password)
|
||||
VALUES
|
||||
('test', 'pbkdf2:sha256:50000$TCI4GzcX$0de171a4f4dac32e3364c7ddc7c14f3e2fa61f2d17574483f7ffbb431b4acb2f'),
|
||||
('other', 'pbkdf2:sha256:50000$kJPKsz6N$d2d4784f1b030a9761f5ccaeeaca413f27f2ecb76d6168407af962ddce849f79');
|
||||
|
||||
INSERT INTO post (title, body, author_id, created)
|
||||
VALUES
|
||||
('test title', 'test' || x'0a' || 'body', 1, '2018-01-01 00:00:00');
|
||||
57
tests/test_auth.py
Normal file
57
tests/test_auth.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import pytest
|
||||
from flask import g, session
|
||||
from flaskr.db import get_db
|
||||
|
||||
|
||||
def test_register(client, app):
|
||||
assert client.get('/auth/register').status_code == 200
|
||||
response = client.post(
|
||||
'/auth/register', data={'username': 'a', 'password': 'a'}
|
||||
)
|
||||
assert response.headers["Location"] == "/auth/login"
|
||||
|
||||
with app.app_context():
|
||||
assert get_db().execute(
|
||||
"SELECT * FROM user WHERE username = 'a'",
|
||||
).fetchone() is not None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(('username', 'password', 'message'), (
|
||||
('', '', b'Username is required.'),
|
||||
('a', '', b'Password is required.'),
|
||||
('test', 'test', b'already registered'),
|
||||
))
|
||||
def test_register_validate_input(client, username, password, message):
|
||||
response = client.post(
|
||||
'/auth/register',
|
||||
data={'username': username, 'password': password}
|
||||
)
|
||||
assert message in response.data
|
||||
|
||||
|
||||
def test_login(client, auth):
|
||||
assert client.get('/auth/login').status_code == 200
|
||||
response = auth.login()
|
||||
assert response.headers["Location"] == "/"
|
||||
|
||||
with client:
|
||||
client.get('/')
|
||||
assert session['user_id'] == 1
|
||||
assert g.user['username'] == 'test'
|
||||
|
||||
|
||||
@pytest.mark.parametrize(('username', 'password', 'message'), (
|
||||
('a', 'test', b'Incorrect username.'),
|
||||
('test', 'a', b'Incorrect password.'),
|
||||
))
|
||||
def test_login_validate_input(auth, username, password, message):
|
||||
response = auth.login(username, password)
|
||||
assert message in response.data
|
||||
|
||||
|
||||
def test_logout(client, auth):
|
||||
auth.login()
|
||||
|
||||
with client:
|
||||
auth.logout()
|
||||
assert 'user_id' not in session
|
||||
93
tests/test_blog.py
Normal file
93
tests/test_blog.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
import pytest
|
||||
from flaskr.db import get_db
|
||||
|
||||
|
||||
def test_index(client, auth):
|
||||
response = client.get('/')
|
||||
assert b"Log In" in response.data
|
||||
assert b"Register" in response.data
|
||||
|
||||
auth.login()
|
||||
response = client.get('/')
|
||||
assert b'Log Out' in response.data
|
||||
assert b'test title' in response.data
|
||||
assert b'by test on 2018-01-01' in response.data
|
||||
assert b'test\nbody' in response.data
|
||||
assert b'href="/1/update"' in response.data
|
||||
|
||||
|
||||
@pytest.mark.parametrize('path', (
|
||||
'/create',
|
||||
'/1/update',
|
||||
'/1/delete',
|
||||
))
|
||||
def test_login_required(client, path):
|
||||
response = client.post(path)
|
||||
assert response.headers["Location"] == "/auth/login"
|
||||
|
||||
|
||||
def test_author_required(app, client, auth):
|
||||
# change the post author to another user
|
||||
with app.app_context():
|
||||
db = get_db()
|
||||
db.execute('UPDATE post SET author_id = 2 WHERE id = 1')
|
||||
db.commit()
|
||||
|
||||
auth.login()
|
||||
# current user can't modify other user's post
|
||||
assert client.post('/1/update').status_code == 403
|
||||
assert client.post('/1/delete').status_code == 403
|
||||
# current user doesn't see edit link
|
||||
assert b'href="/1/update"' not in client.get('/').data
|
||||
|
||||
|
||||
@pytest.mark.parametrize('path', (
|
||||
'/2/update',
|
||||
'/2/delete',
|
||||
))
|
||||
def test_exists_required(client, auth, path):
|
||||
auth.login()
|
||||
assert client.post(path).status_code == 404
|
||||
|
||||
|
||||
def test_create(client, auth, app):
|
||||
auth.login()
|
||||
assert client.get('/create').status_code == 200
|
||||
client.post('/create', data={'title': 'created', 'body': ''})
|
||||
|
||||
with app.app_context():
|
||||
db = get_db()
|
||||
count = db.execute('SELECT COUNT(id) FROM post').fetchone()[0]
|
||||
assert count == 2
|
||||
|
||||
|
||||
def test_update(client, auth, app):
|
||||
auth.login()
|
||||
assert client.get('/1/update').status_code == 200
|
||||
client.post('/1/update', data={'title': 'updated', 'body': ''})
|
||||
|
||||
with app.app_context():
|
||||
db = get_db()
|
||||
post = db.execute('SELECT * FROM post WHERE id = 1').fetchone()
|
||||
assert post['title'] == 'updated'
|
||||
|
||||
|
||||
@pytest.mark.parametrize('path', (
|
||||
'/create',
|
||||
'/1/update',
|
||||
))
|
||||
def test_create_update_validate(client, auth, path):
|
||||
auth.login()
|
||||
response = client.post(path, data={'title': '', 'body': ''})
|
||||
assert b'Title is required.' in response.data
|
||||
|
||||
|
||||
def test_delete(client, auth, app):
|
||||
auth.login()
|
||||
response = client.post('/1/delete')
|
||||
assert response.headers["Location"] == "/"
|
||||
|
||||
with app.app_context():
|
||||
db = get_db()
|
||||
post = db.execute('SELECT * FROM post WHERE id = 1').fetchone()
|
||||
assert post is None
|
||||
28
tests/test_db.py
Normal file
28
tests/test_db.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import sqlite3
|
||||
|
||||
import pytest
|
||||
from flaskr.db import get_db
|
||||
|
||||
|
||||
def test_get_close_db(app):
|
||||
with app.app_context():
|
||||
db = get_db()
|
||||
assert db is get_db()
|
||||
|
||||
with pytest.raises(sqlite3.ProgrammingError) as e:
|
||||
db.execute('SELECT 1')
|
||||
|
||||
assert 'closed' in str(e.value)
|
||||
|
||||
|
||||
def test_init_db_command(runner, monkeypatch):
|
||||
class Recorder(object):
|
||||
called = False
|
||||
|
||||
def fake_init_db():
|
||||
Recorder.called = True
|
||||
|
||||
monkeypatch.setattr('flaskr.db.init_db', fake_init_db)
|
||||
result = runner.invoke(args=['init-db'])
|
||||
assert 'Initialized' in result.output
|
||||
assert Recorder.called
|
||||
11
tests/test_factory.py
Normal file
11
tests/test_factory.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
from flaskr import create_app
|
||||
|
||||
|
||||
def test_config():
|
||||
assert not create_app().testing
|
||||
assert create_app({'TESTING': True}).testing
|
||||
|
||||
|
||||
def test_hello(client):
|
||||
response = client.get('/hello')
|
||||
assert response.data == b'Hello, World!'
|
||||
Loading…
Add table
Add a link
Reference in a new issue