Skip to content

Commit c622931

Browse files
committed
Updated documentation with more explicit discussions on testing
Added unit test to verify command name validation updates.
1 parent 9a20e7c commit c622931

File tree

9 files changed

+95
-9
lines changed

9 files changed

+95
-9
lines changed

docs/api/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ This documentation is for ``cmd2`` version |version|.
3232
py_bridge
3333
table_creator
3434
utils
35+
plugin_external_test
3536

3637
**Modules**
3738

@@ -56,3 +57,4 @@ This documentation is for ``cmd2`` version |version|.
5657
embedded python environment to the host app
5758
- :ref:`api/table_creator:cmd2.table_creator` - table creation module
5859
- :ref:`api/utils:cmd2.utils` - various utility classes and functions
60+
- :ref:`api/plugin_external_test:cmd2_ext_test` - External test plugin

docs/api/plugin_external_test.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
cmd2_ext_test
2+
=============
3+
4+
External Test Plugin
5+
6+
7+
.. autoclass:: cmd2_ext_test.ExternalTestMixin
8+
:members:
9+

docs/features/builtin_commands.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ quit
7070

7171
This command exits the ``cmd2`` application.
7272

73+
.. _feature-builtin-commands-run-pyscript:
74+
7375
run_pyscript
7476
~~~~~~~~~~~~
7577

docs/features/scripting.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ session.
6161
(Cmd) command # this is not a comment
6262

6363

64+
.. _scripting-python-scripts:
65+
6466
Python Scripts
6567
--------------
6668

docs/index.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ Plugins
7676
plugins/index
7777

7878

79+
Testing
80+
=======
81+
82+
.. toctree::
83+
:maxdepth: 2
84+
85+
testing
86+
87+
7988
API Reference
8089
=============
8190

docs/plugins/external_test.rst

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ Overview
55
~~~~~~~~
66

77
.. _cmd2_external_test_plugin:
8-
https://github.com/python-cmd2/cmd2-ext-test/
8+
https://github.com/python-cmd2/cmd2/tree/cmdset_settables/plugins/ext_test
99

10-
The cmd2_external_test_plugin_ supports testing of a cmd2 application by exposing access cmd2 commands with the same
11-
context as from within a cmd2 pyscript. This allows for verification of an application's support for pyscripts and
12-
enables the cmd2 application to be tested as part of a larger system integration test.
10+
The `External Test Plugin <cmd2_external_test_plugin_>`_ supports testing of a cmd2 application by exposing access cmd2
11+
commands with the same context as from within a cmd2 :ref:`Python Scripts <scripting-python-scripts>`. This interface
12+
captures ``stdout``, ``stderr``, as well as any application-specific data returned by the command. This also allows
13+
for verification of an application's support for :ref:`Python Scripts <scripting-python-scripts>` and enables the cmd2
14+
application to be tested as part of a larger system integration test.
1315

1416

1517
Example cmd2 Application
@@ -59,11 +61,11 @@ In your test, define a fixture for your cmd2 application
5961
Writing Tests
6062
~~~~~~~~~~~~~
6163

62-
Now write your tests that validate your application using the `app_cmd` function to access
63-
the cmd2 application's commands. This allows invocation of the application's commands in the
64+
Now write your tests that validate your application using the :meth:`~cmd2_ext_test.ExternalTestMixin.app_cmd()`
65+
function to access the cmd2 application's commands. This allows invocation of the application's commands in the
6466
same format as a user would type. The results from calling a command matches what is returned
65-
from running an python script with cmd2's pyscript command, which provides stdout, stderr, and
66-
the command's result data.
67+
from running an python script with cmd2's :ref:`feature-builtin-commands-run-pyscript` command, which provides
68+
``stdout``, ``stderr``, and the command's result data.
6769

6870
.. code-block:: python
6971

docs/testing.rst

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
Testing
2+
=======
3+
4+
.. toctree::
5+
:maxdepth: 1
6+
7+
Overview
8+
~~~~~~~~
9+
10+
This covers special considerations when writing unit tests for a cmd2 application.
11+
12+
13+
Testing Commands
14+
~~~~~~~~~~~~~~~~
15+
16+
The :doc:`External Test Plugin <plugins/external_test>` provides a mixin class with an :meth:`` function that
17+
allows external calls to application commands. The :meth:`~cmd2_ext_test.ExternalTestMixin.app_cmd()` function captures
18+
and returns stdout, stderr, and the command-specific result data.
19+
20+
21+
Mocking
22+
~~~~~~~
23+
24+
.. _python_mock_autospeccing:
25+
https://docs.python.org/3/library/unittest.mock.html#autospeccing
26+
.. _python_mock_patch:
27+
https://docs.python.org/3/library/unittest.mock.html#patch
28+
29+
If you need to mock anything in your cmd2 application, and most specifically in sub-classes of :class:`~cmd2.Cmd` or
30+
:class:`~cmd2.command_definition.CommandSet`, you must use `Autospeccing <python_mock_autospeccing_>`_,
31+
`spec=True <python_mock_patch_>`_, or whatever equivalant is provided in the mocking library you're using.
32+
33+
In order to automatically load functions as commands cmd2 performs a number of reflection calls to look up attributes
34+
of classes defined in your cmd2 application. Many mocking libraries will automatically create mock objects to match any
35+
attribute being requested, regardless of whether they're present in the object being mocked. This behavior can
36+
incorrectly instruct cmd2 to treat a function or attribute as something it needs to recognize and process. To prevent
37+
this, you should always mock with `Autospeccing <python_mock_autospeccing_>`_ or `spec=True <python_mock_patch_>`_
38+
enabled.
39+
40+
Example of spec=True
41+
====================
42+
.. code-block:: python
43+
44+
def test_mocked_methods():
45+
with mock.patch.object(MockMethodApp, 'foo', spec=True):
46+
cli = MockMethodApp()

noxfile.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ def docs(session):
66
session.install('sphinx',
77
'sphinx-rtd-theme',
88
'.',
9+
'plugins/ext_test',
910
)
1011
session.chdir('docs')
1112
tmpdir = session.create_tmp()

tests/test_parsing.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,15 @@ def test_statement_is_immutable():
836836
statement.raw = 'baz'
837837

838838

839-
def test_is_valid_command_invalid(parser):
839+
def test_is_valid_command_invalid(mocker, parser):
840+
# Non-string command
841+
valid, errmsg = parser.is_valid_command(5)
842+
assert not valid and 'must be a string' in errmsg
843+
844+
mock = mocker.MagicMock()
845+
valid, errmsg = parser.is_valid_command(mock)
846+
assert not valid and 'must be a string' in errmsg
847+
840848
# Empty command
841849
valid, errmsg = parser.is_valid_command('')
842850
assert not valid and 'cannot be an empty string' in errmsg
@@ -871,6 +879,11 @@ def test_is_valid_command_valid(parser):
871879
assert valid
872880
assert not errmsg
873881

882+
# Subcommands can start with shortcut
883+
valid, errmsg = parser.is_valid_command('!subcmd', is_subcommand=True)
884+
assert valid
885+
assert not errmsg
886+
874887

875888
def test_macro_normal_arg_pattern():
876889
# This pattern matches digits surrounded by exactly 1 brace on a side and 1 or more braces on the opposite side

0 commit comments

Comments
 (0)