交付流程 · 產物閱讀
PYexamples/quality-workflow/independent/cases.py

cases.py

"""Business assertions defined from the frozen contract, not response snapshots."""

from concurrent.futures import ThreadPoolExecutor
from threading import Barrier
import unittest

from .fixture import PaymentEnvironment


CASE_IDS = {
    "reject_paid_order": "BE-PAID-REJECT",
    "pay_pending_order": "BE-PENDING-PAY",
    "concurrent_payment_once": "BE-CONCURRENT",
    "reject_invalid_request": "BE-INVALID-REQUEST",
    "reject_missing_order": "BE-MISSING-ORDER",
}


class PaymentContract(unittest.TestCase):
    implementation = None
    fault = "none"

    def setUp(self):
        self.environment = PaymentEnvironment(self.implementation, self.fault)
        self.addCleanup(self.environment.close)
        self.api = self.environment.adapter

    def test_reject_paid_order(self):
        before = self.api.observe("paid-order")
        status, body = self.api.pay({"order_id": "paid-order"})
        self.assertEqual(status, 409, "Paid order must return HTTP 409")
        self.assertEqual(body.get("error"), "ORDER_ALREADY_PAID", "Paid rejection must explain its cause")
        self.assertEqual(self.api.observe("paid-order"), before, "Rejected payment must not change DB state")

    def test_pay_pending_order(self):
        status, body = self.api.pay({"order_id": "pending-order"})
        self.assertEqual(status, 200)
        self.assertEqual(body, {"order_id": "pending-order", "status": "PAID"})
        self.assertEqual(self.api.observe("pending-order"), {"status": "PAID", "payments": 1})

    def test_concurrent_payment_once(self):
        barrier = Barrier(2)

        def pay_together():
            barrier.wait(timeout=5)
            return self.api.pay({"order_id": "pending-order"})

        with ThreadPoolExecutor(max_workers=2) as executor:
            results = list(executor.map(lambda _: pay_together(), range(2)))
        self.assertEqual(sorted(status for status, _ in results), [200, 409])
        self.assertEqual(self.api.observe("pending-order"), {"status": "PAID", "payments": 1},
                         "Concurrent requests must create exactly one payment")

    def test_reject_invalid_request(self):
        before = self.api.observe("pending-order")
        status, body = self.api.pay({"order_id": ""})
        self.assertEqual((status, body), (400, {"error": "INVALID_REQUEST"}))
        self.assertEqual(self.api.observe("pending-order"), before)

    def test_reject_missing_order(self):
        status, body = self.api.pay({"order_id": "unknown-order"})
        self.assertEqual((status, body), (404, {"error": "ORDER_NOT_FOUND"}))
        self.assertEqual(self.api.observe("unknown-order"), {"status": None, "payments": 0})

靜態唯讀副本 · 可直接開啟,不需伺服器;不改變核准或執行結果