6
FIXME: This will become a manual for writing test suites in yarn. It
7
is currently not yet written.
11
This manual will provide all the information needed by Yarn users to enable
12
them to use Yarn effectively in their development projects.
14
The information will be
20
The information will include details of
22
* how to perform certain tasks
23
* why things are done in particular ways
32
* this Document Status section
37
* Test Language Specification
47
* `yarn`'s command line
48
* How to embed `yarn` in Markdown
55
`yarn` is a scenario testing tool: you write a scenario describing how a
56
user uses your software and what should happen, and express, using
57
very lightweight syntax, the scenario in such a way that it can be tested
58
automatically. The scenario has a simple, but strict structure:
60
SCENARIO name of scenario
61
GIVEN some setup for the test
62
WHEN thing that is to be tested happens
63
THEN the post-conditions must be true
65
As an example, consider a very short test scenario for verifying that
66
a backup program works, at least for one simple case.
68
SCENARIO basic backup and restore
69
GIVEN some live data in a directory
70
AND an empty backup repository
72
THEN the data can be restored
74
(Note the addition of AND: you can have multiple GIVEN, WHEN, and
75
THEN statements. The AND keyword makes the text be more readable.)
78
### Who is `yarn` for?
80
### Who are the test suites written in `yarn` for?
82
### What kinds of testing is `yarn` for?
84
### Why `yarn` instead of other tools?
91
Scenarios are meant to be written in mostly human readable language.
92
However, they are not free form text. In addition to the GIVEN/WHEN/THEN
93
structure, the text for each of the steps needs a computer-executable
94
implementation. This is done by using IMPLEMENTS. The backup scenario
95
from above might be implemented as follows:
97
IMPLEMENTS GIVEN some live data in a directory
98
rm -rf "$DATADIR/data"
100
echo foo > "$DATADIR/data/foo"
102
IMPLEMENTS GIVEN an empty backup repository
103
rm -rf "$DATADIR/repo"
104
mkdir "$DATADIR/repo"
106
IMPLEMENTS WHEN a backup is made
107
backup-program -r "$DATADIR/repo" "$DATADIR/data"
109
IMPLEMENTS THEN the data can be restored
110
mkdir "$DATADIR/restored"
111
restore-program -r "$DATADIR/repo" "$DATADIR/restored"
112
diff -rq "$DATADIR/data" "$DATADIR/restored"
114
Each "IMPLEMENT GIVEN" (or WHEN, THEN) is followed by a regular
115
expression on the same line, and then a shell script that gets executed
116
to implement any step that matches the regular expression. The
117
implementation can extract data from the match as well: for example,
118
the regular expression might allow a file size to be specified.
120
The above example seems a bit silly, of course: why go to the effort
121
to obfuscate the various steps? The answer is that the various steps,
122
implemented using IMPLEMENTS, can be combined in many ways, to test
123
different aspects of the program being tested. In effect, the IMPLEMENTS
124
sections provide a vocabulary which the scenario writer can use to
125
express a variety of usefully different scenarios, which together
126
test all the aspects of the software that need to be tested.
128
Moreover, by making the step descriptions be human language
129
text, matched by regular expressions, most of the test can
130
hopefully be written, and understood, by non-programmers. Someone
131
who understands what a program should do, could write tests
132
to verify its behaviour. The implementations of the various
133
steps need to be implemented by a programmer, but given a
134
well-designed set of steps, with enough flexibility in their
135
implementation, that quite a good test suite can be written.
137
### Test Language Specification
139
A test document is written in [Markdown][markdown], with block
140
quoted code blocks being interpreted specially. Each block
141
must follow the syntax defined here.
143
* Every step in a scenario is one line, and starts with a keyword.
145
* Each implementation (IMPLEMENTS) starts as a new block, and
146
continues until there is a block that starts with another
149
The following keywords are defined.
151
* **SCENARIO** starts a new scenario. The rest of the line is the name of
152
the scenario. The name is used for documentation and reporting
153
purposes only and has no semantic meaning. SCENARIO MUST be the
154
first keyword in a scenario, with the exception of IMPLEMENTS.
155
The set of documents passed in a test run may define any number of
156
scenarios between them, but there must be at least one or it is a
157
test failure. The IMPLEMENTS sections are shared between the
158
documents and scenarios.
160
* **ASSUMING** defines a condition for the scenario. The rest of the
161
line is "matched text", which gets implemented by an
162
IMPLEMENTS section. If the code executed by the implementation
163
fails, the scenario is skipped.
165
* **GIVEN** prepares the world for the test to run. If
166
the implementation fails, the scenario fails.
168
* **WHEN** makes the change to the world that is to be tested.
169
If the code fails, the scenario fails.
171
* **THEN** verifies that the changes made by the GIVEN steps
172
did the right thing. If the code fails, the scenario fails.
174
* **FINALLY** specifies how to clean up after a scenario. If the code
175
fails, the scenario fails. All FINALLY blocks get run either when
176
encountered in the scenario flow, or at the end of the scenario,
177
regardless of whether the scenario is failing or not.
179
* **AND** acts as ASSUMING, GIVEN, WHEN, THEN, or FINALLY: whichever
180
was used last. It must not be used unless the previous step was
181
one of those, or another AND.
183
* **IMPLEMENTS** is followed by one of ASSUMING, GIVEN, WHEN, or THEN,
184
and a PCRE regular expression, all on one line, and then further
185
lines of shell commands until the end of the block quoted code
186
block. Markdown is unclear whether an empty line (no characters,
187
not even whitespace) between two block quoted code blocks starts a
188
new one or not, so we resolve the ambiguity by specifiying that a
189
code block directly following a code block is a continuation unless
190
it starts with one of the scenario testing keywords.
192
The shell commands get parenthesised parts of the match of the
193
regular expression as environment variables (`$MATCH_1` etc). For
194
example, if the regexp is "a (\d+) byte file", then `$MATCH_1` gets
195
set to the number matched by `\d+`.
197
The test runner creates a temporary directory, whose name is
198
given to the shell code in the `DATADIR` environment variable.
200
The test runner sets the `SRCDIR` environment variable to the
201
path to the directory it was invoked from (by convention, the
202
root of the source tree of the project).
204
The test runner removes all other environment variables, except
205
`TERM`, `USER`, `USERNAME`, `LOGNAME`, `HOME`, and `PATH`. It also
206
forces `SHELL` set to `/bin/sh`, and `LC_ALL` set to `C`, in order
207
to have as clean an environment as possible for tests to run in.
209
The shell commands get invoked with `/bin/sh -eu`, and need to
210
be written accordingly. Be careful about commands that return a
211
non-zero exit code. There will eventually be a library of shell
212
functions supplied which allow handling the testing of non-zero
213
exit codes cleanly. In addition functions for handling stdout and
214
stderr will be provided.
216
The code block of an IMPLEMENTS block fails if the shell
217
invocation exits with a non-zero exit code. Output to stderr is
218
not an indication of failure. Any output to stdout or stderr may
219
or may not be shown to the user.
223
* The name of each scenario (given with SCENARIO) must be unique.
224
* All names of scenarios and steps will be normalised before use
225
(whitespace collapse, leading and trailing whitespace
226
* Every ASSUMING, GIVEN, WHEN, THEN, FINALLY must be matched by
227
exactly one IMPLEMENTS. The test runner checks this before running
229
* Every IMPLEMENTS may match any number of ASSUMING, GIVEN, WHEN,
230
THEN, or FINALLY. The test runner may warn if an IMPLEMENTS is unused.
231
* If ASSUMING fails, that scenario is skipped, and any FINALLY steps
242
- who are the test suites written in yarn for?
243
- what kinds of testing is yarn for?
244
- why yarn instead of other tools?
246
- NOT installation instructions
248
- a test suite for "hello world"
249
- make the files available so people can try things for themselves
250
- a few simple scenarios
251
* The yarn testing language
252
- Markdown with blockquotes for the executable code
253
- SCENARIO + the step-wise keywords
254
- IMPLEMENTS sections
256
- command line syntax
257
- examples of various ways to run yarn in different scenarios:
258
- how to run just one scenario
259
- how to run yarn under cron or jenkins
260
- formatting a test suite in yarn with pandoc
262
- this chapter will describe best practices for writing test suites
264
- how to structure the files: what to put in each *.yarn file, e.g.,
265
where should IMPLEMENTS go
266
- how to write test suites that make it easy to debug things when a
268
- good phrasing guidelines for yarn scenario names and step names
269
- what things are good to keep visible to the reader, what are
270
better hidden inside impementations of steps, with examples from
271
real projects using yarn
272
- guidelines for well-defined steps that are easy to understand and
274
- anti-patterns: things that are good to avoid
276
- make test code be obviously correct; make test code be the best
278
- when is it OK to skip scenarios?
280
- this chapter will discuss ways to use yarn in things that are not
281
just "run this program and examine the output"
282
- start a daemon in the background, kill it at the end of a scenario
283
- how to use a really heavy-weight thing in test suites (e.g., start
284
a database server for all scenarios to share)