Files
xiaoxia-saas/tests/unit/test_exceptions_domain.py
CI Bot f55d0d6f0e
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Successful in 33s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 1m5s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 59s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m0s
CI/CD Pipeline / Validate - Code Quality (push) Failing after 3m6s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 1m58s
CI/CD Pipeline / Unit Tests (push) Failing after 4m39s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 5m20s
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Integration Tests (push) Successful in 2m51s
CI/CD Pipeline / Build Staging API Image (push) Successful in 15m48s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m45s
CI/CD Pipeline / ACR Image Cleanup (push) Failing after 15s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 2m56s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 5m6s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
style: auto-format with black + isort + prettier
2026-07-25 16:17:09 +00:00

167 lines
5.1 KiB
Python
Executable File

"""领域层异常类单元测试."""
import pytest
from packages.domain.exceptions import (
DomainError,
NotFoundError,
QuotaExceededError,
ValidationError,
)
class TestDomainError:
"""领域异常基类测试."""
def test_is_exception(self):
"""DomainError 继承自 Exception."""
err = DomainError("test")
assert isinstance(err, Exception)
def test_message(self):
"""可以设置错误消息."""
err = DomainError("something wrong")
assert str(err) == "something wrong"
def test_empty_message(self):
"""支持空消息."""
err = DomainError()
assert str(err) == ""
def test_can_be_raised(self):
"""可以被 raise 和 catch."""
with pytest.raises(DomainError) as exc_info:
raise DomainError("oops")
assert str(exc_info.value) == "oops"
class TestNotFoundError:
"""资源不存在异常测试."""
def test_inherits_domain_error(self):
"""NotFoundError 继承自 DomainError."""
err = NotFoundError("user not found")
assert isinstance(err, DomainError)
assert isinstance(err, Exception)
def test_message(self):
"""错误消息正确."""
err = NotFoundError("project 123 not found")
assert str(err) == "project 123 not found"
assert "123" in str(err)
def test_can_catch_as_domain_error(self):
"""可以用 DomainError 捕获."""
with pytest.raises(DomainError):
raise NotFoundError("not found")
class TestValidationError:
"""校验失败异常测试."""
def test_inherits_domain_error(self):
"""ValidationError 继承自 DomainError."""
err = ValidationError("invalid input")
assert isinstance(err, DomainError)
def test_message(self):
"""错误消息正确."""
msg = "name must not be empty"
err = ValidationError(msg)
assert str(err) == msg
def test_not_not_found(self):
"""ValidationError 不是 NotFoundError."""
err = ValidationError("bad")
assert not isinstance(err, NotFoundError)
class TestQuotaExceededError:
"""配额超限异常测试."""
def test_inherits_domain_error(self):
"""QuotaExceededError 继承自 DomainError."""
err = QuotaExceededError("storage", 100.0, 150.0)
assert isinstance(err, DomainError)
def test_dimension_attribute(self):
"""保存 dimension 属性."""
err = QuotaExceededError("storage", 100.0, 150.0)
assert err.dimension == "storage"
def test_limit_attribute(self):
"""保存 limit 属性."""
err = QuotaExceededError("storage", 100.0, 150.0)
assert err.limit == 100.0
def test_used_attribute(self):
"""保存 used 属性."""
err = QuotaExceededError("storage", 100.0, 150.0)
assert err.used == 150.0
def test_message_format(self):
"""错误消息格式正确."""
err = QuotaExceededError("credits", 50.0, 75.0)
msg = str(err)
assert "credits" in msg
assert "50" in msg
assert "75" in msg
assert "Quota exceeded" in msg
def test_zero_limit(self):
"""limit 为 0 的情况."""
err = QuotaExceededError("test", 0.0, 1.0)
assert err.limit == 0.0
assert err.used == 1.0
assert "0" in str(err)
def test_equal_limit_and_used(self):
"""used 刚好等于 limit(边界情况)."""
err = QuotaExceededError("test", 100.0, 100.0)
assert err.used == 100.0
assert err.limit == 100.0
def test_integer_values(self):
"""整数值也能正常工作."""
err = QuotaExceededError("count", 10, 20)
assert err.dimension == "count"
assert err.limit == 10
assert err.used == 20
def test_can_catch_as_domain_error(self):
"""可以用 DomainError 捕获."""
with pytest.raises(DomainError):
raise QuotaExceededError("x", 1.0, 2.0)
class TestExceptionHierarchy:
"""异常继承关系验证."""
def test_all_are_domain_errors(self):
"""所有领域异常都是 DomainError."""
errors = [
NotFoundError("test"),
ValidationError("test"),
QuotaExceededError("test", 1, 2),
]
for err in errors:
assert isinstance(err, DomainError)
def test_all_are_exceptions(self):
"""所有领域异常都是 Exception."""
errors = [
DomainError("test"),
NotFoundError("test"),
ValidationError("test"),
QuotaExceededError("test", 1, 2),
]
for err in errors:
assert isinstance(err, Exception)
def test_not_found_is_not_validation(self):
"""不同异常类型不能互相混淆."""
assert not isinstance(NotFoundError("x"), ValidationError)
assert not isinstance(ValidationError("x"), NotFoundError)
assert not isinstance(QuotaExceededError("x", 1, 2), NotFoundError)
assert not isinstance(QuotaExceededError("x", 1, 2), ValidationError)