This commit is contained in:
@@ -30,6 +30,7 @@ class todocreate(BaseModel):
|
|||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class todoupdate(BaseModel):
|
class todoupdate(BaseModel):
|
||||||
completion: bool | None = None
|
completion: bool | None = None
|
||||||
task: str | None = Field(
|
task: str | None = Field(
|
||||||
@@ -48,16 +49,15 @@ class todoupdate(BaseModel):
|
|||||||
raise ValueError("task must not be blank")
|
raise ValueError("task must not be blank")
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
@model_validator(mode="after")
|
@model_validator(mode="after")
|
||||||
def at_least_one_field_must_be_provided(self) -> Self:
|
def at_least_one_field_must_be_provided(self) -> Self:
|
||||||
if self.task is None and self.completion is None:
|
if self.task is None and self.completion is None:
|
||||||
raise ValueError(
|
raise ValueError("task or completion must be provided")
|
||||||
"task or completion must be provided"
|
|
||||||
)
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
class todoresponse(BaseModel):
|
class todoresponse(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
task: str
|
task: str
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ class FakeScalarResult:
|
|||||||
def all(self) -> list[Todo]:
|
def all(self) -> list[Todo]:
|
||||||
return self.todos
|
return self.todos
|
||||||
|
|
||||||
|
|
||||||
class FakeSession:
|
class FakeSession:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.todo_to_return: Todo | None = None
|
self.todo_to_return: Todo | None = None
|
||||||
|
|||||||
@@ -8,19 +8,23 @@ def test_todocreate_requires_task() -> None:
|
|||||||
with pytest.raises(ValidationError):
|
with pytest.raises(ValidationError):
|
||||||
todocreate()
|
todocreate()
|
||||||
|
|
||||||
|
|
||||||
def test_todocreate_accepts_valid_task() -> None:
|
def test_todocreate_accepts_valid_task() -> None:
|
||||||
todo_data = todocreate(task = "学习测试单元")
|
todo_data = todocreate(task="学习测试单元")
|
||||||
|
|
||||||
assert todo_data.task == "学习测试单元"
|
assert todo_data.task == "学习测试单元"
|
||||||
|
|
||||||
|
|
||||||
def test_todocreate_rejects_empty_task() -> None:
|
def test_todocreate_rejects_empty_task() -> None:
|
||||||
with pytest.raises(ValidationError):
|
with pytest.raises(ValidationError):
|
||||||
todocreate(task="")
|
todocreate(task="")
|
||||||
|
|
||||||
|
|
||||||
def test_todocreate_rejects_blank_task() -> None:
|
def test_todocreate_rejects_blank_task() -> None:
|
||||||
with pytest.raises(ValidationError):
|
with pytest.raises(ValidationError):
|
||||||
todocreate(task=" ")
|
todocreate(task=" ")
|
||||||
|
|
||||||
|
|
||||||
def test_todocreate_rejects_task_longer_than_200_characters() -> None:
|
def test_todocreate_rejects_task_longer_than_200_characters() -> None:
|
||||||
long_task = "a" * 201
|
long_task = "a" * 201
|
||||||
|
|
||||||
|
|||||||
+48
-32
@@ -7,17 +7,17 @@ from tests.fakes import FakeSession
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"invalid_task",
|
"invalid_task",
|
||||||
[
|
[
|
||||||
"",
|
"",
|
||||||
" ",
|
" ",
|
||||||
"a" * 201,
|
"a" * 201,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_create_todo_rejects_invalid_task(
|
def test_create_todo_rejects_invalid_task(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
invalid_task:str,
|
invalid_task: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
response = client.post(
|
response = client.post(
|
||||||
"/todos",
|
"/todos",
|
||||||
json={"task": invalid_task},
|
json={"task": invalid_task},
|
||||||
@@ -25,9 +25,10 @@ def test_create_todo_rejects_invalid_task(
|
|||||||
|
|
||||||
assert response.status_code == 422
|
assert response.status_code == 422
|
||||||
|
|
||||||
|
|
||||||
def test_create_todo_rejects_missing_task(
|
def test_create_todo_rejects_missing_task(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
) -> None:
|
) -> None:
|
||||||
response = client.post(
|
response = client.post(
|
||||||
"/todos",
|
"/todos",
|
||||||
json={},
|
json={},
|
||||||
@@ -40,6 +41,7 @@ def test_create_todo_rejects_missing_task(
|
|||||||
assert error["loc"] == ["body", "task"]
|
assert error["loc"] == ["body", "task"]
|
||||||
assert error["type"] == "missing"
|
assert error["type"] == "missing"
|
||||||
|
|
||||||
|
|
||||||
def test_create_todo_success(
|
def test_create_todo_success(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -51,13 +53,14 @@ def test_create_todo_success(
|
|||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == {
|
assert response.json() == {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"task": "学习单元测试",
|
"task": "学习单元测试",
|
||||||
"completion": False,
|
"completion": False,
|
||||||
}
|
}
|
||||||
assert fake_session.committed is True
|
assert fake_session.committed is True
|
||||||
assert fake_session.added_todo.task == "学习单元测试"
|
assert fake_session.added_todo.task == "学习单元测试"
|
||||||
|
|
||||||
|
|
||||||
def test_patch_missing_todo_returns_404(
|
def test_patch_missing_todo_returns_404(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -76,6 +79,7 @@ def test_patch_missing_todo_returns_404(
|
|||||||
assert fake_session.committed is False
|
assert fake_session.committed is False
|
||||||
assert fake_session.rolled_back is False
|
assert fake_session.rolled_back is False
|
||||||
|
|
||||||
|
|
||||||
def test_patch_existing_todo_updates_task(
|
def test_patch_existing_todo_updates_task(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -93,13 +97,14 @@ def test_patch_existing_todo_updates_task(
|
|||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == {
|
assert response.json() == {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"task": "新任务",
|
"task": "新任务",
|
||||||
"completion": False,
|
"completion": False,
|
||||||
}
|
}
|
||||||
assert fake_session.committed is True
|
assert fake_session.committed is True
|
||||||
assert fake_session.todo_to_return.task == "新任务"
|
assert fake_session.todo_to_return.task == "新任务"
|
||||||
|
|
||||||
|
|
||||||
def test_patch_existing_todo_updates_completion_only(
|
def test_patch_existing_todo_updates_completion_only(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -117,14 +122,15 @@ def test_patch_existing_todo_updates_completion_only(
|
|||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == {
|
assert response.json() == {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"task": "保留原任务",
|
"task": "保留原任务",
|
||||||
"completion": True,
|
"completion": True,
|
||||||
}
|
}
|
||||||
assert fake_session.committed is True
|
assert fake_session.committed is True
|
||||||
assert fake_session.todo_to_return.task == "保留原任务"
|
assert fake_session.todo_to_return.task == "保留原任务"
|
||||||
assert fake_session.todo_to_return.completion is True
|
assert fake_session.todo_to_return.completion is True
|
||||||
|
|
||||||
|
|
||||||
def test_delete_existing_todo_success(
|
def test_delete_existing_todo_success(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -140,13 +146,14 @@ def test_delete_existing_todo_success(
|
|||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == {
|
assert response.json() == {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"task": "准备删除的任务",
|
"task": "准备删除的任务",
|
||||||
"completion": False,
|
"completion": False,
|
||||||
}
|
}
|
||||||
assert fake_session.committed is True
|
assert fake_session.committed is True
|
||||||
assert fake_session.deleted_todo is existing_todo
|
assert fake_session.deleted_todo is existing_todo
|
||||||
|
|
||||||
|
|
||||||
def test_delete_missing_todo_returns_404(
|
def test_delete_missing_todo_returns_404(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -161,6 +168,7 @@ def test_delete_missing_todo_returns_404(
|
|||||||
assert fake_session.deleted_todo is None
|
assert fake_session.deleted_todo is None
|
||||||
assert fake_session.committed is False
|
assert fake_session.committed is False
|
||||||
|
|
||||||
|
|
||||||
def test_create_todo_rolls_back_when_commit_fails(
|
def test_create_todo_rolls_back_when_commit_fails(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -176,6 +184,7 @@ def test_create_todo_rolls_back_when_commit_fails(
|
|||||||
assert fake_session.rolled_back is True
|
assert fake_session.rolled_back is True
|
||||||
assert fake_session.committed is False
|
assert fake_session.committed is False
|
||||||
|
|
||||||
|
|
||||||
def test_patch_todo_rolls_back_when_commit_fails(
|
def test_patch_todo_rolls_back_when_commit_fails(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -196,6 +205,7 @@ def test_patch_todo_rolls_back_when_commit_fails(
|
|||||||
assert fake_session.rolled_back is True
|
assert fake_session.rolled_back is True
|
||||||
assert fake_session.committed is False
|
assert fake_session.committed is False
|
||||||
|
|
||||||
|
|
||||||
def test_delete_todo_rolls_back_when_commit_fails(
|
def test_delete_todo_rolls_back_when_commit_fails(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -215,6 +225,7 @@ def test_delete_todo_rolls_back_when_commit_fails(
|
|||||||
assert fake_session.rolled_back is True
|
assert fake_session.rolled_back is True
|
||||||
assert fake_session.committed is False
|
assert fake_session.committed is False
|
||||||
|
|
||||||
|
|
||||||
def test_get_todos_returns_todo_list(
|
def test_get_todos_returns_todo_list(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -248,6 +259,7 @@ def test_get_todos_returns_todo_list(
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_get_todos_returns_empty_list(
|
def test_get_todos_returns_empty_list(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -259,6 +271,7 @@ def test_get_todos_returns_empty_list(
|
|||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == []
|
assert response.json() == []
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"invalid_task",
|
"invalid_task",
|
||||||
[
|
[
|
||||||
@@ -285,6 +298,7 @@ def test_patch_todo_rejects_invalid_task(
|
|||||||
|
|
||||||
assert response.status_code == 422
|
assert response.status_code == 422
|
||||||
|
|
||||||
|
|
||||||
def test_patch_todo_rejects_empty_body(
|
def test_patch_todo_rejects_empty_body(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -303,6 +317,7 @@ def test_patch_todo_rejects_empty_body(
|
|||||||
assert response.status_code == 422
|
assert response.status_code == 422
|
||||||
assert fake_session.committed is False
|
assert fake_session.committed is False
|
||||||
|
|
||||||
|
|
||||||
def test_patch_todo_accepts_completion_false(
|
def test_patch_todo_accepts_completion_false(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -323,6 +338,7 @@ def test_patch_todo_accepts_completion_false(
|
|||||||
assert response.json()["completion"] is False
|
assert response.json()["completion"] is False
|
||||||
assert fake_session.committed is True
|
assert fake_session.committed is True
|
||||||
|
|
||||||
|
|
||||||
def test_patch_todo_updates_task_and_completion(
|
def test_patch_todo_updates_task_and_completion(
|
||||||
client: TestClient,
|
client: TestClient,
|
||||||
fake_session: FakeSession,
|
fake_session: FakeSession,
|
||||||
@@ -344,10 +360,10 @@ def test_patch_todo_updates_task_and_completion(
|
|||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.json() == {
|
assert response.json() == {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"task": "修改后的任务",
|
"task": "修改后的任务",
|
||||||
"completion": True,
|
"completion": True,
|
||||||
}
|
}
|
||||||
assert existing_todo.task == "修改后的任务"
|
assert existing_todo.task == "修改后的任务"
|
||||||
assert existing_todo.completion is True
|
assert existing_todo.completion is True
|
||||||
assert fake_session.committed is True
|
assert fake_session.committed is True
|
||||||
|
|||||||
@@ -8,14 +8,16 @@ def test_todoupdate_rejects_empty_update() -> None:
|
|||||||
with pytest.raises(ValidationError):
|
with pytest.raises(ValidationError):
|
||||||
todoupdate()
|
todoupdate()
|
||||||
|
|
||||||
|
|
||||||
def test_todoupdate_accepts_provided_value() -> None:
|
def test_todoupdate_accepts_provided_value() -> None:
|
||||||
update_data = todoupdate(
|
update_data = todoupdate(
|
||||||
task = "学习测试单元",
|
task="学习测试单元",
|
||||||
completion = True,
|
completion=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert update_data.task == "学习测试单元"
|
assert update_data.task == "学习测试单元"
|
||||||
|
|
||||||
|
|
||||||
def test_todoupdate_accepts_task_only() -> None:
|
def test_todoupdate_accepts_task_only() -> None:
|
||||||
update_data = todoupdate(task="修改后的任务")
|
update_data = todoupdate(task="修改后的任务")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user