diff --git a/python/t/CMDTEST_exit_nonzero.py b/python/t/CMDTEST_exit_nonzero.py
new file mode 100644
index 0000000..aa5d2c6
--- /dev/null
+++ b/python/t/CMDTEST_exit_nonzero.py
@@ -0,0 +1,42 @@
+
+from selftest_utils import SelftestUtils
+
+class TC_exit_nonzero(SelftestUtils, TestCase):
+
+    def test_exit_nonzero_CORRECT(self):
+        self.create_CMDTEST_foo(
+            'with self.cmd("false") as c:',
+            '    c.exit_nonzero()',
+        )
+
+        with self.cmd_cmdtest() as c:
+            c.stdout_equal([
+                "### cmdline: false",
+            ])
+
+    def test_exit_nonzero_INCORRECT(self):
+        self.create_CMDTEST_foo(
+            'with self.cmd("true") as c:',
+            '    c.exit_nonzero()',
+        )
+
+        with self.cmd_cmdtest() as c:
+            c.stdout_equal([
+                "### cmdline: true",
+                "--- ERROR: exit_nonzero",
+                "actual: 0",
+                "expect: <nonzero value>",
+                "",
+            ])
+            c.exit_nonzero()
+
+    def test_exit_nonzero_CORRECT_18(self):
+        self.create_CMDTEST_foo(
+            'with self.cmd("exit 18") as c:',
+            '    c.exit_nonzero()',
+        )
+
+        with self.cmd_cmdtest() as c:
+            c.stdout_equal([
+                "### cmdline: exit 18",
+            ])
diff --git a/python/t/CMDTEST_exit_zero.py b/python/t/CMDTEST_exit_zero.py
new file mode 100644
index 0000000..a64c94b
--- /dev/null
+++ b/python/t/CMDTEST_exit_zero.py
@@ -0,0 +1,47 @@
+
+from selftest_utils import SelftestUtils
+
+class TC_exit_zero(SelftestUtils, TestCase):
+
+    def test_exit_zero_CORRECT(self):
+        self.create_CMDTEST_foo(
+            'with self.cmd("true") as c:',
+            '    c.exit_zero()',
+        )
+
+        with self.cmd_cmdtest() as c:
+            c.stdout_equal([
+                "### cmdline: true",
+            ])
+
+    def test_exit_zero_INCORRECT(self):
+        self.create_CMDTEST_foo(
+            'with self.cmd("false") as c:',
+            '    c.exit_zero()',
+        )
+
+        with self.cmd_cmdtest() as c:
+            c.stdout_equal([
+                "### cmdline: false",
+                "--- ERROR: exit_zero",
+                "actual: 1",
+                "expect: 0",
+                "",
+            ])
+            c.exit_nonzero()
+
+    def test_exit_zero_INCORRECT_18(self):
+        self.create_CMDTEST_foo(
+            'with self.cmd("exit 18") as c:',
+            '    c.exit_zero()',
+        )
+
+        with self.cmd_cmdtest() as c:
+            c.stdout_equal([
+                "### cmdline: exit 18",
+                "--- ERROR: exit_zero",
+                "actual: 18",
+                "expect: 0",
+                "",
+            ])
+            c.exit_nonzero()
diff --git a/python/t/CMDTEST_stdout_equal.py b/python/t/CMDTEST_stdout_equal.py
new file mode 100644
index 0000000..7807ff2
--- /dev/null
+++ b/python/t/CMDTEST_stdout_equal.py
@@ -0,0 +1,71 @@
+
+from selftest_utils import SelftestUtils
+
+class TC_stdout_equal(SelftestUtils, TestCase):
+
+    def test_stdout_equal_CORRECT_EMPTY(self):
+        self.create_CMDTEST_foo(
+            'with self.cmd("true") as c:',
+            '    c.stdout_equal([',
+            '    ])',
+        )
+
+        with self.cmd_cmdtest() as c:
+            c.stdout_equal([
+                "### cmdline: true",
+            ])
+
+    def test_stdout_equal_INCORRECT_EMPTY(self):
+        self.create_CMDTEST_foo(
+            'with self.cmd("echo hello") as c:',
+            '    c.stdout_equal([',
+            '    ])',
+        )
+
+        with self.cmd_cmdtest() as c:
+            c.stdout_equal([
+                "### cmdline: echo hello",
+                "--- ERROR: stdout_equal",
+                "actual:",
+                "     hello",
+                "expect:",
+                "     <<empty>>",
+            ])
+            c.exit_nonzero()
+
+    def test_stdout_equal_CORRECT_2_LINES(self):
+        self.create_CMDTEST_foo(
+            'with self.cmd("echo hello && echo world") as c:',
+            '    c.stdout_equal([',
+            '        "hello",',
+            '        "world",',
+            '    ])',
+        )
+
+        with self.cmd_cmdtest() as c:
+            c.stdout_equal([
+                "### cmdline: echo hello && echo world",
+            ])
+
+    def test_stdout_equal_INCORRECT_2_LINES(self):
+        self.create_CMDTEST_foo(
+            'with self.cmd("echo hello && echo world && echo MORE") as c:',
+            '    c.stdout_equal([',
+            '        "hello",',
+            '        "world",',
+            '    ])',
+        )
+
+        with self.cmd_cmdtest() as c:
+            c.stdout_equal([
+                "### cmdline: echo hello && echo world && echo MORE",
+                "--- ERROR: stdout_equal",
+                "actual:",
+                "     hello",
+                "     world",
+                "     MORE",
+                "expect:",
+                "     hello",
+                "     world",
+            ])
+            c.exit_nonzero()
diff --git a/python/t/selftest_utils.py b/python/t/selftest_utils.py
new file mode 100644
index 0000000..f11f347
--- /dev/null
+++ b/python/t/selftest_utils.py
@@ -0,0 +1,30 @@
+
+import os
+from contextlib import contextmanager
+
+TOP = os.getcwd()
+
+class SelftestUtils:
+
+    def setup(self):
+        self.always_ignore_file('tmp-cmdtest-python/')
+
+    def create_CMDTEST_foo(self, *lines):
+        self.create_file("CMDTEST_foo.py", [
+            "class TC_foo(TestCase):",
+            "    def setup(self):",
+            "        #prepend_path #{BIN.inspect}",
+            "        #prepend_path #{PLATFORM_BIN.inspect}",
+            "        pass",
+            "",
+            "    def test_foo(self):",
+            [ "        " + line for line in lines],
+        ])
+
+    @contextmanager
+    def cmd_cmdtest(self, *args):
+        cmdtest = "%s/cmdtest.py" % TOP
+        command = "%s --quiet CMDTEST_foo.py" % cmdtest
+        cmdline = ' '.join([command] + list(args))
+        with self.cmd(cmdline) as c:
+            yield c