Testing Web Applications
The test client
def test_home_page_loads(client):
resp = client.get("/")
assert resp.status_code == 200
assert b"PandaDev" in resp.data
Logging in during tests
def login(client, email, password="CorrectHorse9!"):
return client.post("/auth/login", data={"email": email, "password": password},
follow_redirects=True)
CSRF in tests
Most apps disable CSRF in the testing config (WTF_CSRF_ENABLED = False) for convenience. Keep at least one test with it enabled to prove protection works:
def test_post_without_csrf_token_is_rejected(app, client):
app.config["WTF_CSRF_ENABLED"] = True
resp = client.post("/collaboration", data={"email": "a@b.com"})
assert resp.status_code == 400
Test permissions explicitly
Security bugs are usually missing checks. For every protected route, test each kind of user:
import pytest
@pytest.mark.parametrize("role, expected", [
(None, 404), # anonymous: the admin area does not reveal itself
("user", 404),
("sub_admin", 403), # staff without this permission
("admin", 200),
])
def test_staff_page_access(client, make_user, role, expected):
if role:
make_user(f"{role}@example.com", role=role)
login(client, f"{role}@example.com")
assert client.get("/admin/staff").status_code == expected
Also test ownership: user A must not see or edit user B's data by changing an ID in the URL. That bug class (IDOR) is one of the most common real-world vulnerabilities.
Test the database effects
def test_review_approval_updates_rating(client, admin, project, review):
client.post(f"/admin/reviews/{review.id}/approve")
db.session.refresh(project)
assert project.rating_count == 1
Assert on what changed in the database, not only on the response.
Test input handling
- Malformed query strings:
/projects/filter?category=abcshould return 200 or 400, never 500. - Over-long input, unicode, HTML and script tags in text fields.
- Missing required fields.
A smoke test that requests every GET route as each kind of user and asserts no 500s catches a surprising number of bugs cheaply.
Exercise
Write tests for a "delete my comment" route: the owner can delete, another user gets 403 or 404, an anonymous user is redirected to login, and the comment is really gone from the database afterwards.
進捗はこのブラウザーにのみ保存されます。
レビューに提出(10 ポイント)