diff --git a/tests/test_expand_dbd.py b/tests/test_expand_dbd.py
new file mode 100644
index 0000000000000000000000000000000000000000..eae44dee4933da57f30e07c7f2130ff15f553cc5
--- /dev/null
+++ b/tests/test_expand_dbd.py
@@ -0,0 +1,60 @@
+import os
+import subprocess
+from pathlib import Path
+
+import pytest
+
+
+@pytest.fixture
+def expanddbdtcl():
+    require_path = Path(os.environ.get("E3_REQUIRE_LOCATION"))
+    expanddbdtcl = require_path / "tools" / "expandDBD.tcl"
+    assert expanddbdtcl.is_file() and os.access(expanddbdtcl, os.X_OK)
+    return expanddbdtcl
+
+
+def test_missing_dbd_file(tmpdir, expanddbdtcl):
+    dbd_file = Path(tmpdir) / "tmp.dbd"
+    dbd_file.write_text("include not_a_file.dbd")
+    result = subprocess.run(
+        [expanddbdtcl, dbd_file],
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        encoding="utf-8",
+    )
+    assert result.returncode == 1
+    assert "file not_a_file.dbd not found" in result.stderr
+
+
+def test_include_dbd_file(tmpdir, expanddbdtcl):
+    dbd_a = Path(tmpdir) / "a.dbd"
+    dbd_a.write_text("include b.dbd")
+
+    dbd_b = Path(tmpdir) / "b.dbd"
+    dbd_b.write_text("content")
+
+    result = subprocess.run(
+        [expanddbdtcl, "-I", str(tmpdir), dbd_a],
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        encoding="utf-8",
+    )
+    assert result.returncode == 0
+    assert "content" == result.stdout.strip("\n")
+
+
+def test_skip_repeated_includes(tmpdir, expanddbdtcl):
+    dbd_a = Path(tmpdir) / "a.dbd"
+    dbd_a.write_text("include b.dbd\ninclude b.dbd")
+
+    dbd_b = Path(tmpdir) / "b.dbd"
+    dbd_b.touch()
+
+    result = subprocess.run(
+        [expanddbdtcl, "-I", str(tmpdir), dbd_a],
+        stdout=subprocess.PIPE,
+        stderr=subprocess.PIPE,
+        encoding="utf-8",
+    )
+    assert result.returncode == 0
+    assert "Info: skipping duplicate file b.dbd included from" in result.stderr