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 अंक)