如何使用 Fast API 中的夹具和 pytest 在单个测试中跳过身份验证?
How can I skip authentication in a single test with a fixture in Fast API together with pytest?
我已经构建了类似于 documentation 中描述的身份验证。所以我从那里复制了这个依赖项:
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except JWTError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
raise credentials_exception
return user
我在一组端点中使用,例如,在文档的另一个示例中,对于 User
我有 GET
、POST
、PUT
, DELETE
和 GET ALL
.
唯一不需要身份验证的方法是 POST 创建新用户的方法。
我希望能够定义单元测试来验证未经身份验证无法访问的方法,并且当我专注于方法的内容时我想完全跳过身份验证。
因此我在夹具中使用了覆盖功能。例如这个测试:
test_user.py
def test_create_user(test_db, create_user, user, skip_authentication):
"""
Verify a user can be created and retrieved
"""
response = client.post(
"/api/v1/users/",
json=create_user,
)
# Assert creation
assert response.status_code == 200, response.text
data = response.json()
assert "id" in data
user_id = data["id"]
del data["id"]
assert data == user
# Assert get user
response = client.get(f"/api/v1/users/{user_id}")
assert response.status_code == 200, response.text
data = response.json()
assert user_id == data["id"]
del data["id"]
assert data == user
conftest.py
@pytest.fixture
def skip_authentication() -> None:
def get_current_user():
pass
app.dependency_overrides[get_current_active_user] = get_current_user
这似乎可以删除身份验证,但它在所有测试中都将其删除,而不仅仅是在具有夹具 skip_authentication
的测试中。
如何将其限制为仅我想要的测试?
根据@MatsLindh 的评论,我能够让它工作。我不确定这是否是理想的解决方案,但对我有用。
我创建了两个装置,一个用于经过身份验证的用户,另一个用于其他测试:
conftest.py
@pytest.fixture
def client():
"""
Return an API Client
"""
app.dependency_overrides = {}
return TestClient(app)
@pytest.fixture
def client_authenticated():
"""
Returns an API client which skips the authentication
"""
def skip_auth():
pass
app.dependency_overrides[get_current_active_user] = skip_auth
return TestClient(app)
然后我能够测试我的正常测试并验证身份验证:
def test_premissions_user(client, test_db, create_user):
"""
Verify that not logged in users can not access the user functions excluding create
"""
# Create user
response = client.post(
"/api/v1/users/",
json=create_user
)
assert response.status_code == 200, response.text
# Get all users
response = client.get(
"/api/v1/users/",
)
assert response.status_code == 401, response.text
# Get user 1
response = client.get(
"/api/v1/users/1",
)
assert response.status_code == 401, response.text
# Delete user 1
response = client.get(
"/api/v1/users/1",
)
assert response.status_code == 401, response.text
# Modify user 1
response = client.delete(
"/api/v1/users/1",
)
assert response.status_code == 401, response.text
def test_premissions_user_authenticated(client_authenticated, test_db, create_user):
"""
Verify that not logged in users can not access the user functions excluding create
"""
# Create user
response = client_authenticated.post(
"/api/v1/users/",
json=create_user
)
assert response.status_code == 200, response.text
# Get all users
response = client_authenticated.get(
"/api/v1/users/",
)
assert response.status_code == 200, response.text
# Get user 1
response = client_authenticated.get(
"/api/v1/users/1",
)
assert response.status_code == 200, response.text
# Delete user 1
response = client_authenticated.get(
"/api/v1/users/1",
)
assert response.status_code == 200, response.text
# Modify user 1
response = client_authenticated.delete(
"/api/v1/users/1",
)
assert response.status_code == 204, response.text
我创建了 pytest-fastapi-deps 库,它允许轻松定义和清理 FastAPI 依赖项。
像这样使用它只会影响一个测试:
def test_create_user(test_db, create_user, user, fastapi_dep):
"""
Verify a user can be created and retrieved
"""
def skip_auth():
pass
with fastapi_dep(app).override({get_current_active_user: skip_auth}):
response = client.post(
"/api/v1/users/",
json=create_user,
)
# Assert creation
assert response.status_code == 200, response.text
data = response.json()
assert "id" in data
user_id = data["id"]
del data["id"]
assert data == user
# Assert get user
response = client.get(f"/api/v1/users/{user_id}")
assert response.status_code == 200, response.text
data = response.json()
assert user_id == data["id"]
del data["id"]
assert data == user
我已经构建了类似于 documentation 中描述的身份验证。所以我从那里复制了这个依赖项:
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except JWTError:
raise credentials_exception
user = get_user(fake_users_db, username=token_data.username)
if user is None:
raise credentials_exception
return user
我在一组端点中使用,例如,在文档的另一个示例中,对于 User
我有 GET
、POST
、PUT
, DELETE
和 GET ALL
.
唯一不需要身份验证的方法是 POST 创建新用户的方法。
我希望能够定义单元测试来验证未经身份验证无法访问的方法,并且当我专注于方法的内容时我想完全跳过身份验证。
因此我在夹具中使用了覆盖功能。例如这个测试:
test_user.py
def test_create_user(test_db, create_user, user, skip_authentication):
"""
Verify a user can be created and retrieved
"""
response = client.post(
"/api/v1/users/",
json=create_user,
)
# Assert creation
assert response.status_code == 200, response.text
data = response.json()
assert "id" in data
user_id = data["id"]
del data["id"]
assert data == user
# Assert get user
response = client.get(f"/api/v1/users/{user_id}")
assert response.status_code == 200, response.text
data = response.json()
assert user_id == data["id"]
del data["id"]
assert data == user
conftest.py
@pytest.fixture
def skip_authentication() -> None:
def get_current_user():
pass
app.dependency_overrides[get_current_active_user] = get_current_user
这似乎可以删除身份验证,但它在所有测试中都将其删除,而不仅仅是在具有夹具 skip_authentication
的测试中。
如何将其限制为仅我想要的测试?
根据@MatsLindh 的评论,我能够让它工作。我不确定这是否是理想的解决方案,但对我有用。
我创建了两个装置,一个用于经过身份验证的用户,另一个用于其他测试:
conftest.py
@pytest.fixture
def client():
"""
Return an API Client
"""
app.dependency_overrides = {}
return TestClient(app)
@pytest.fixture
def client_authenticated():
"""
Returns an API client which skips the authentication
"""
def skip_auth():
pass
app.dependency_overrides[get_current_active_user] = skip_auth
return TestClient(app)
然后我能够测试我的正常测试并验证身份验证:
def test_premissions_user(client, test_db, create_user):
"""
Verify that not logged in users can not access the user functions excluding create
"""
# Create user
response = client.post(
"/api/v1/users/",
json=create_user
)
assert response.status_code == 200, response.text
# Get all users
response = client.get(
"/api/v1/users/",
)
assert response.status_code == 401, response.text
# Get user 1
response = client.get(
"/api/v1/users/1",
)
assert response.status_code == 401, response.text
# Delete user 1
response = client.get(
"/api/v1/users/1",
)
assert response.status_code == 401, response.text
# Modify user 1
response = client.delete(
"/api/v1/users/1",
)
assert response.status_code == 401, response.text
def test_premissions_user_authenticated(client_authenticated, test_db, create_user):
"""
Verify that not logged in users can not access the user functions excluding create
"""
# Create user
response = client_authenticated.post(
"/api/v1/users/",
json=create_user
)
assert response.status_code == 200, response.text
# Get all users
response = client_authenticated.get(
"/api/v1/users/",
)
assert response.status_code == 200, response.text
# Get user 1
response = client_authenticated.get(
"/api/v1/users/1",
)
assert response.status_code == 200, response.text
# Delete user 1
response = client_authenticated.get(
"/api/v1/users/1",
)
assert response.status_code == 200, response.text
# Modify user 1
response = client_authenticated.delete(
"/api/v1/users/1",
)
assert response.status_code == 204, response.text
我创建了 pytest-fastapi-deps 库,它允许轻松定义和清理 FastAPI 依赖项。
像这样使用它只会影响一个测试:
def test_create_user(test_db, create_user, user, fastapi_dep):
"""
Verify a user can be created and retrieved
"""
def skip_auth():
pass
with fastapi_dep(app).override({get_current_active_user: skip_auth}):
response = client.post(
"/api/v1/users/",
json=create_user,
)
# Assert creation
assert response.status_code == 200, response.text
data = response.json()
assert "id" in data
user_id = data["id"]
del data["id"]
assert data == user
# Assert get user
response = client.get(f"/api/v1/users/{user_id}")
assert response.status_code == 200, response.text
data = response.json()
assert user_id == data["id"]
del data["id"]
assert data == user