summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/api/index.rst2
-rw-r--r--docs/api/plugin_external_test.rst9
-rw-r--r--docs/features/builtin_commands.rst2
-rw-r--r--docs/features/scripting.rst2
-rw-r--r--docs/index.rst9
-rw-r--r--docs/plugins/external_test.rst18
-rw-r--r--docs/testing.rst46
-rw-r--r--noxfile.py1
-rwxr-xr-xtests/test_parsing.py15
9 files changed, 95 insertions, 9 deletions
diff --git a/docs/api/index.rst b/docs/api/index.rst
index 17a25907..1a49adfa 100644
--- a/docs/api/index.rst
+++ b/docs/api/index.rst
@@ -32,6 +32,7 @@ This documentation is for ``cmd2`` version |version|.
py_bridge
table_creator
utils
+ plugin_external_test
**Modules**
@@ -56,3 +57,4 @@ This documentation is for ``cmd2`` version |version|.
embedded python environment to the host app
- :ref:`api/table_creator:cmd2.table_creator` - table creation module
- :ref:`api/utils:cmd2.utils` - various utility classes and functions
+- :ref:`api/plugin_external_test:cmd2_ext_test` - External test plugin
diff --git a/docs/api/plugin_external_test.rst b/docs/api/plugin_external_test.rst
new file mode 100644
index 00000000..58450b11
--- /dev/null
+++ b/docs/api/plugin_external_test.rst
@@ -0,0 +1,9 @@
+cmd2_ext_test
+=============
+
+External Test Plugin
+
+
+.. autoclass:: cmd2_ext_test.ExternalTestMixin
+ :members:
+
diff --git a/docs/features/builtin_commands.rst b/docs/features/builtin_commands.rst
index e08b5c24..d5112458 100644
--- a/docs/features/builtin_commands.rst
+++ b/docs/features/builtin_commands.rst
@@ -70,6 +70,8 @@ quit
This command exits the ``cmd2`` application.
+.. _feature-builtin-commands-run-pyscript:
+
run_pyscript
~~~~~~~~~~~~
diff --git a/docs/features/scripting.rst b/docs/features/scripting.rst
index 141eaa62..f92942be 100644
--- a/docs/features/scripting.rst
+++ b/docs/features/scripting.rst
@@ -61,6 +61,8 @@ session.
(Cmd) command # this is not a comment
+.. _scripting-python-scripts:
+
Python Scripts
--------------
diff --git a/docs/index.rst b/docs/index.rst
index 9153c47f..30584f42 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -76,6 +76,15 @@ Plugins
plugins/index
+Testing
+=======
+
+.. toctree::
+ :maxdepth: 2
+
+ testing
+
+
API Reference
=============
diff --git a/docs/plugins/external_test.rst b/docs/plugins/external_test.rst
index 74407b97..ac0026c6 100644
--- a/docs/plugins/external_test.rst
+++ b/docs/plugins/external_test.rst
@@ -5,11 +5,13 @@ Overview
~~~~~~~~
.. _cmd2_external_test_plugin:
- https://github.com/python-cmd2/cmd2-ext-test/
+ https://github.com/python-cmd2/cmd2/tree/cmdset_settables/plugins/ext_test
-The cmd2_external_test_plugin_ supports testing of a cmd2 application by exposing access cmd2 commands with the same
-context as from within a cmd2 pyscript. This allows for verification of an application's support for pyscripts and
-enables the cmd2 application to be tested as part of a larger system integration test.
+The `External Test Plugin <cmd2_external_test_plugin_>`_ supports testing of a cmd2 application by exposing access cmd2
+commands with the same context as from within a cmd2 :ref:`Python Scripts <scripting-python-scripts>`. This interface
+captures ``stdout``, ``stderr``, as well as any application-specific data returned by the command. This also allows
+for verification of an application's support for :ref:`Python Scripts <scripting-python-scripts>` and enables the cmd2
+application to be tested as part of a larger system integration test.
Example cmd2 Application
@@ -59,11 +61,11 @@ In your test, define a fixture for your cmd2 application
Writing Tests
~~~~~~~~~~~~~
-Now write your tests that validate your application using the `app_cmd` function to access
-the cmd2 application's commands. This allows invocation of the application's commands in the
+Now write your tests that validate your application using the :meth:`~cmd2_ext_test.ExternalTestMixin.app_cmd()`
+function to access the cmd2 application's commands. This allows invocation of the application's commands in the
same format as a user would type. The results from calling a command matches what is returned
-from running an python script with cmd2's pyscript command, which provides stdout, stderr, and
-the command's result data.
+from running an python script with cmd2's :ref:`feature-builtin-commands-run-pyscript` command, which provides
+``stdout``, ``stderr``, and the command's result data.
.. code-block:: python
diff --git a/docs/testing.rst b/docs/testing.rst
new file mode 100644
index 00000000..811e1137
--- /dev/null
+++ b/docs/testing.rst
@@ -0,0 +1,46 @@
+Testing
+=======
+
+.. toctree::
+ :maxdepth: 1
+
+Overview
+~~~~~~~~
+
+This covers special considerations when writing unit tests for a cmd2 application.
+
+
+Testing Commands
+~~~~~~~~~~~~~~~~
+
+The :doc:`External Test Plugin <plugins/external_test>` provides a mixin class with an :meth:`` function that
+allows external calls to application commands. The :meth:`~cmd2_ext_test.ExternalTestMixin.app_cmd()` function captures
+and returns stdout, stderr, and the command-specific result data.
+
+
+Mocking
+~~~~~~~
+
+.. _python_mock_autospeccing:
+ https://docs.python.org/3/library/unittest.mock.html#autospeccing
+.. _python_mock_patch:
+ https://docs.python.org/3/library/unittest.mock.html#patch
+
+If you need to mock anything in your cmd2 application, and most specifically in sub-classes of :class:`~cmd2.Cmd` or
+:class:`~cmd2.command_definition.CommandSet`, you must use `Autospeccing <python_mock_autospeccing_>`_,
+`spec=True <python_mock_patch_>`_, or whatever equivalant is provided in the mocking library you're using.
+
+In order to automatically load functions as commands cmd2 performs a number of reflection calls to look up attributes
+of classes defined in your cmd2 application. Many mocking libraries will automatically create mock objects to match any
+attribute being requested, regardless of whether they're present in the object being mocked. This behavior can
+incorrectly instruct cmd2 to treat a function or attribute as something it needs to recognize and process. To prevent
+this, you should always mock with `Autospeccing <python_mock_autospeccing_>`_ or `spec=True <python_mock_patch_>`_
+enabled.
+
+Example of spec=True
+====================
+.. code-block:: python
+
+ def test_mocked_methods():
+ with mock.patch.object(MockMethodApp, 'foo', spec=True):
+ cli = MockMethodApp()
diff --git a/noxfile.py b/noxfile.py
index 7d51a948..a46c008e 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -6,6 +6,7 @@ def docs(session):
session.install('sphinx',
'sphinx-rtd-theme',
'.',
+ 'plugins/ext_test',
)
session.chdir('docs')
tmpdir = session.create_tmp()
diff --git a/tests/test_parsing.py b/tests/test_parsing.py
index c2c242fe..62982ab5 100755
--- a/tests/test_parsing.py
+++ b/tests/test_parsing.py
@@ -836,7 +836,15 @@ def test_statement_is_immutable():
statement.raw = 'baz'
-def test_is_valid_command_invalid(parser):
+def test_is_valid_command_invalid(mocker, parser):
+ # Non-string command
+ valid, errmsg = parser.is_valid_command(5)
+ assert not valid and 'must be a string' in errmsg
+
+ mock = mocker.MagicMock()
+ valid, errmsg = parser.is_valid_command(mock)
+ assert not valid and 'must be a string' in errmsg
+
# Empty command
valid, errmsg = parser.is_valid_command('')
assert not valid and 'cannot be an empty string' in errmsg
@@ -871,6 +879,11 @@ def test_is_valid_command_valid(parser):
assert valid
assert not errmsg
+ # Subcommands can start with shortcut
+ valid, errmsg = parser.is_valid_command('!subcmd', is_subcommand=True)
+ assert valid
+ assert not errmsg
+
def test_macro_normal_arg_pattern():
# This pattern matches digits surrounded by exactly 1 brace on a side and 1 or more braces on the opposite side