1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
========================
Transcript based testing
========================
A transcript is both the input and output of a successful session of a
``cmd2``-based app which is saved to a text file. The transcript can be played
back into the app as a unit test. You can embed regular expressions into the
transcript to accomodate commands that produce dynamic or variable output.
Creating a transcript
=====================
Here's a transcript created from ``python examples/example.py``:
.. code-block:: none
(Cmd) say -r 3 Goodnight, Gracie
Goodnight, Gracie
Goodnight, Gracie
Goodnight, Gracie
(Cmd) mumble maybe we could go to lunch
like maybe we ... could go to hmmm lunch
(Cmd) mumble maybe we could go to lunch
well maybe we could like go to er lunch right?
This transcript has three commands: you can see them on the lines that begin
with the prompt, which in this case is ``(Cmd) ``. Following each command is
the output generated by that command.
Any lines in the transcript before the first line that begins with the prompt
are ignored. You can take advantage of this by using the first lines of the
transcript as comments.
.. code-block:: none
# Lines at the beginning of the transcript that do not
; start with the prompt i.e. '(Cmd) ' are ignored.
/* You can use them for comments. */
All six of these lines before the first prompt are treated as comments.
(Cmd) say -r 3 Goodnight, Gracie
Goodnight, Gracie
Goodnight, Gracie
Goodnight, Gracie
(Cmd) mumble maybe we could go to lunch
like maybe we ... could go to hmmm lunch
(Cmd) mumble maybe we could go to lunch
maybe we could like go to er lunch right?
In this example I've used several different commenting styles, and even bare
text. It doesn't matter what you put on those beginning lines. Everything before
the first line that starts with ``(Cmd) `` will be ignored.
If we used this transcript as-is, it would likely fail. As you can see, the
``mumble`` command doesn't always return the same thing. The ``mumble`` command
inserts random words into the input. Transcripts can include regular
expressions as a way to check for output that can change.
Regular expressions can be included in the response portion of a transcript,
and are surrounded by slashes.
.. code-block:: none
(Cmd) mumble maybe we could go to lunch
/.*\bmaybe\b.*\bcould\b.*\blunch\b.*/
(Cmd) mumble maybe we could go to lunch
/.*\bmaybe\b.*\bcould\b.*\blunch\b.*/
Without creating a tutorial on regular expressions, this one matches anything
that has the words `maybe`, `could`, and `lunch` in that order. It doesn't
ensure that `we` or `go` or `to` appear in the output, but it does work if
mumble happens to add words to the beginning or the end of the output.
Since the output could be multiple lines long, ``cmd2`` uses multiline regular
expression matching, and also uses the ``DOTALL`` flag, which subtly changes the behavior of commonly
used special characters like `.`, `^` and `$`, so you may want to double check the
`Python regular expression documentation
<https://docs.python.org/3/library/re.html>`_.
If your output has slashes in it, you will need to escape those slashes so the
stuff between them is not interpred as a regular expression. In this transcript::
(Cmd) say cd /usr/local/lib/python3.6/site-packages
/usr/local/lib/python3.6/site-packages
the output contains slashes. The text between the first slash and the second
slash, (``usr``) will be interpreted as a regular expression, and those two
slashes will not be included in the comparison. When replayed, this transcript
would therefore fail. To fix it, we could either write a regular expression to
match the path instead of specifying it verbatim, or we can escape the slashes::
(Cmd) say cd /usr/local/lib/python3.6/site-packages
\/usr\/local\/lib\/python3.6\/site-packages
Running a transcript
====================
Once you have created a transcript, it's easy to have your application play it
back and check the output. From within the ``examples/`` directory:
.. code-block:: none
$ python example.py --test transcript_regex.txt
.
----------------------------------------------------------------------
Ran 1 test in 0.013s
OK
The output will look familiar if you use ``unittest``, because that's exactly
what happens. Each command in the transcript is run, and the output is
``asserted`` to match expected result from the transcript.
.. note::
If you have set ``allow_cli_args`` to False in order to disable parsing of
command line arguments at invocation, then the use of ``-t`` or ``--test``
to run transcript testing is automatically disabled. In this case, you can
alternatively provide a value for the optional ``transcript_files`` when
constructing the instance of your ``cmd2.Cmd`` derived class in order to
cause a transcript test to run::
from cmd2 import Cmd
class App(Cmd):
# customized attributes and methods here
if __name__ == '__main__':
app = App(transcript_files=['exampleSession.txt'])
app.cmdloop()
|