    def test_crud(self, api):
        r = api.post("/subjects", headers=H(api),
                     json={"subject": "Invoice %RandomInvoiceNumber% due"})
        assert r.status_code in (200, 201), r.text
        sid = sub_id_of(r)

        assert any(s["id"] == sid for s in api.get("/subjects/list").json()["subjects"])

        r3 = api.put(f"/subjects/{sid}", headers=H(api), json={"subject": "Updated subject"})
        assert r3.status_code == 200, r3.text

        r4 = api.get(f"/subjects/{sid}")
        assert r4.status_code == 200
        assert r4.json()["subject"] == "Updated subject"

        r5 = api.delete(f"/subjects/{sid}", headers=H(api))
        assert r5.status_code == 200
        assert all(s["id"] != sid for s in api.get("/subjects/list").json()["subjects"])

    def test_empty_subject_rejected(self, api):
        r = api.post("/subjects", headers=H(api), json={"subject": ""})
