diff --git a/src/test/README b/src/test/README
new file mode 100644
index 0000000..8e02014
--- /dev/null
+++ b/src/test/README
@@ -0,0 +1,10 @@
+Liza Testing Library
+====================
+
+This namespace contains a library to aid in the testing of code that _makes
+use of_ Liza. Especially due to legacy reasons, there are some parts of the
+system that are quite difficult to mock and work with.
+
+For test cases of Liza itself, see `/test' in the project root (sibling of
+`/src').
+
diff --git a/src/test/program/DummyClassifier.js b/src/test/program/DummyClassifier.js
new file mode 100644
index 0000000..871d4fe
--- /dev/null
+++ b/src/test/program/DummyClassifier.js
@@ -0,0 +1,7 @@
+/**
+ * Dummpy classifier for TestProgram
+ */
+
+module.exports = function() {};
+module.exports.knownFields = {};
+
diff --git a/src/test/program/Program.js b/src/test/program/Program.js
new file mode 100644
index 0000000..b62dc7d
--- /dev/null
+++ b/src/test/program/Program.js
@@ -0,0 +1,30 @@
+/**
+ * Mockable Program
+ *
+ * Copyright (C) 2017 LoVullo Associates, Inc.
+ *
+ * This file is part of liza.
+ *
+ * liza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+"use strict";
+
+
+module.exports = program_path => require( program_path )
+ .extend(
+{
+ classifier: __dirname + '/DummyClassifier',
+} );
+
diff --git a/src/test/program/util.js b/src/test/program/util.js
new file mode 100644
index 0000000..f583032
--- /dev/null
+++ b/src/test/program/util.js
@@ -0,0 +1,252 @@
+/**
+ * Utility functions for Program testing
+ *
+ * Copyright (C) 2017 LoVullo Associates, Inc.
+ *
+ * This file is part of liza.
+ *
+ * liza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+'use strict';
+
+
+// N.B.: if the step titles change, these keys will change; we consider this
+// to be acceptable because, if steps change, the tests will also likely
+// change, and this is the only unique identifier we have (perhaps another
+// can be added in the future that won't change)
+exports.stepNameIdMap = Sut => Sut().steps.reduce(
+ ( result, { title }, step_id ) =>
+ {
+ result[ title.replace( ' ', '_' ) ] = step_id;
+ return result;
+ },
+ {}
+);
+
+
+/**
+ * Run tests against Program assertions
+ *
+ * Provided will be an expect-style testing framework and a Program
+ * SUT, along with a descriptor-providing callback `descf`. The callback
+ * will be invoked with certain useful information (like a step map) and is
+ * expected to return an array of test descriptors, which are of the format:
+ *
+ * ```
+ * { label,
+ * event,
+ * step_id,
+ * data