README
1NAME
2
3 Test::Auto - Test Automation
4
5ABSTRACT
6
7 Test Automation, Docs Generation
8
9SYNOPSIS
10
11 #!/usr/bin/env perl
12
13 use Test::Auto;
14 use Test::More;
15
16 my $test = Test::Auto->new(
17 't/Test_Auto.t'
18 );
19
20 # automation
21
22 # my $subtests = $test->subtests->standard;
23
24 # ...
25
26 # done_testing;
27
28DESCRIPTION
29
30 This package aims to provide, a standard for documenting Perl 5
31 software projects, a framework writing tests, test automation, and
32 documentation generation.
33
34REASONING
35
36 This framework lets you write documentation in test files using
37 pod-like comment blocks. By using a particular set of comment blocks
38 (the specification) this framework can run certain kinds of tests
39 automatically. For example, we can automatically ensure that the
40 package the test is associated with is loadable, that the test file
41 comment blocks meet the specification, that any super-classes or
42 libraries are loadable, and that the functions, methods, and routines
43 are properly documented.
44
45LIBRARIES
46
47 This package uses type constraints from:
48
49 Test::Auto::Types
50
51SCENARIOS
52
53 This package supports the following scenarios:
54
55 exports
56
57 use Test::Auto;
58 use Test::More;
59
60 my $subtests = testauto 't/Test_Auto.t';
61
62 # automation
63
64 # $subtests->standard;
65
66 # ...
67
68 # done_testing;
69
70 This package automatically exports the testauto function which uses the
71 "current file" as the automated testing source.
72
73ATTRIBUTES
74
75 This package has the following attributes:
76
77 data
78
79 data(Data)
80
81 This attribute is read-only, accepts (Data) values, and is optional.
82
83 file
84
85 file(Str)
86
87 This attribute is read-only, accepts (Str) values, and is required.
88
89FUNCTIONS
90
91 This package implements the following functions:
92
93 testauto
94
95 testauto(Str $file) : Subtests
96
97 This function is exported automatically and returns a
98 Test::Auto::Subtests object for the test file given.
99
100 testauto example #1
101
102 # given: synopsis
103
104 my $subtests = testauto 't/Test_Auto.t';
105
106METHODS
107
108 This package implements the following methods:
109
110 document
111
112 document() : Document
113
114 This method returns a Test::Auto::Document object.
115
116 document example #1
117
118 # given: synopsis
119
120 my $document = $test->document;
121
122 parser
123
124 parser() : Parser
125
126 This method returns a Test::Auto::Parser object.
127
128 parser example #1
129
130 # given: synopsis
131
132 my $parser = $test->parser;
133
134 subtests
135
136 subtests() : Subtests
137
138 This method returns a Test::Auto::Subtests object.
139
140 subtests example #1
141
142 # given: synopsis
143
144 my $subtests = $test->subtests;
145
146SPECIFICATION
147
148 # [required]
149
150 =name
151 =abstract
152 =tagline
153 =includes
154 =synopsis
155 =description
156
157 # [optional]
158
159 =libraries
160 =inherits
161 =integrates
162 =attributes
163
164 # [repeatable; optional]
165
166 =scenario $name
167 =example $name
168
169 # [repeatable; optional]
170
171 =method $name
172 =signature $name
173 =example-$number $name # [repeatable]
174
175 # [repeatable; optional]
176
177 =function $name
178 =signature $name
179 =example-$number $name # [repeatable]
180
181 # [repeatable; optional]
182
183 =routine $name
184 =signature $name
185 =example-$number $name # [repeatable]
186
187 # [repeatable; optional]
188
189 =type $name
190 =type-library $name
191 =type-composite $name # [optional]
192 =type-parent $name # [optional]
193 =type-coercion-$number $name # [optional]
194 =type-example-$number $name # [repeatable]
195
196 The specification is designed to accommodate typical package
197 declarations. It is used by the parser to provide the content used in
198 the test automation and document generation. Note: when code blocks are
199 evaluated "redefined" warnings are now automatically disabled.
200
201 name
202
203 =name
204
205 Path::Find
206
207 =cut
208
209 The name block should contain the package name. This is tested for
210 loadability.
211
212 tagline
213
214 =tagline
215
216 Path Finder
217
218 =cut
219
220 The tagline block should contain a tagline for the package. This is
221 optional but if present is concatenated with the name during POD
222 generation.
223
224 abstract
225
226 =abstract
227
228 Find Paths using Heuristics
229
230 =cut
231
232 The abstract block should contain a subtitle describing the package.
233 This is tested for existence.
234
235 includes
236
237 =includes
238
239 function: path
240 method: children
241 method: siblings
242 method: new
243
244 =cut
245
246 The includes block should contain a list of function, method, and/or
247 routine names in the format of $type: $name. Empty lines are ignored.
248 This is tested for existence. Each function, method, and/or routine is
249 tested to be documented properly. Also, the package must recognize that
250 each exists.
251
252 synopsis
253
254 =synopsis
255
256 use Path::Find 'path';
257
258 my $path = path; # get path using cwd
259
260 =cut
261
262 The synopsis block should contain the normative usage of the package.
263 This is tested for existence. This block should be written in a way
264 that allows it to be evaled successfully and should return a value.
265
266 description
267
268 =description
269
270 interdum posuere lorem ipsum dolor sit amet consectetur adipiscing elit duis
271 tristique sollicitudin nibh sit amet
272
273 =cut
274
275 The description block should contain a thorough explanation of the
276 purpose of the package. This is tested for existence.
277
278 libraries
279
280 =libraries
281
282 Types::Standard
283 Types::TypeTiny
284
285 =cut
286
287 The libraries block should contain a list of packages, each of which is
288 itself a Type::Library. These packages are tested for loadability, and
289 to ensure they are type library classes.
290
291 inherits
292
293 =inherits
294
295 Path::Tiny
296
297 =cut
298
299 The inherits block should contain a list of parent packages. These
300 packages are tested for loadability.
301
302 integrates
303
304 =integrates
305
306 Path::Find::Upable
307 Path::Find::Downable
308
309 =cut
310
311 The integrates block should contain a list of packages that are
312 involved in the behavior of the main package. These packages are not
313 automatically tested.
314
315 scenarios
316
317 =scenario export-path-make
318
319 quisque egestas diam in arcu cursus euismod quis viverra nibh
320
321 =example export-path-make
322
323 # given: synopsis
324
325 package main;
326
327 use Path::Find 'path_make';
328
329 path_make 'relpath/to/file';
330
331 =cut
332
333 There are situation where a package can be configured in different
334 ways, especially where it exists without functions, methods or routines
335 for the purpose of configuring the environment. The scenario directive
336 can be used to automate testing and documenting package usages and
337 configurations.Describing a scenario requires two blocks, i.e. scenario
338 $name and example $name. The scenario block should contain a
339 description of the scenario and its purpose. The example block must
340 exist when documenting a method and should contain valid Perl code and
341 return a value. The block may contain a "magic" comment in the form of
342 given: synopsis or given: example $name which if present will include
343 the given code example(s) with the evaluation of the current block.
344 Each scenario is tested and must be recognized to exist by the main
345 package.
346
347 attributes
348
349 =attributes
350
351 cwd: ro, req, Object
352
353 =cut
354
355 The attributes block should contain a list of package attributes in the
356 form of $name: $is, $presence, $type, where $is should be ro
357 (read-only) or rw (read-wire), and $presence should be req (required)
358 or opt (optional), and $type can be any valid Type::Tiny expression.
359 Each attribute declaration must be recognized to exist by the main
360 package and have a type which is recognized by one of the declared type
361 libraries.
362
363 methods
364
365 =method children
366
367 quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat
368
369 =signature children
370
371 children() : [Object]
372
373 =example-1 children
374
375 # given: synopsis
376
377 my $children = $path->children;
378
379 =example-2 children
380
381 # given: synopsis
382
383 my $filtered = $path->children(qr/lib/);
384
385 =cut
386
387 Describing a method requires at least three blocks, i.e. method $name,
388 signature $name, and example-1 $name. The method block should contain a
389 description of the method and its purpose. The signature block should
390 contain a method signature in the form of $signature : $return_type,
391 where $signature is a valid typed signature and $return_type is any
392 valid Type::Tiny expression. The example-$number block is a repeatable
393 block, and at least one block must exist when documenting a method. The
394 example-$number block should contain valid Perl code and return a
395 value. The block may contain a "magic" comment in the form of given:
396 synopsis or given: example-$number $name which if present will include
397 the given code example(s) with the evaluation of the current block.
398 Each method is tested and must be recognized to exist by the main
399 package.
400
401 functions
402
403 =function path
404
405 lectus quam id leo in vitae turpis massa sed elementum tempus egestas
406
407 =signature children
408
409 path() : Object
410
411 =example-1 path
412
413 package Test::Path::Find;
414
415 use Path::Find;
416
417 my $path = path;
418
419 =cut
420
421 Describing a function requires at least three blocks, i.e. function
422 $name, signature $name, and example-1 $name. The function block should
423 contain a description of the function and its purpose. The signature
424 block should contain a function signature in the form of $signature :
425 $return_type, where $signature is a valid typed signature and
426 $return_type is any valid Type::Tiny expression. The example-$number
427 block is a repeatable block, and at least one block must exist when
428 documenting a function. The example-$number block should contain valid
429 Perl code and return a value. The block may contain a "magic" comment
430 in the form of given: synopsis or given: example-$number $name which if
431 present will include the given code example(s) with the evaluation of
432 the current block. Each function is tested and must be recognized to
433 exist by the main package.
434
435 routines
436
437 =routine algorithms
438
439 sed sed risus pretium quam vulputate dignissim suspendisse in est ante
440
441 =signature algorithms
442
443 algorithms() : Object
444
445 =example-1 algorithms
446
447 # given: synopsis
448
449 $path->algorithms
450
451 =example-2 algorithms
452
453 package Test::Path::Find;
454
455 use Path::Find;
456
457 Path::Find->algorithms;
458
459 =cut
460
461 Typically, a Perl subroutine is declared as a function or a method.
462 Rarely, but sometimes necessary, you will need to describe a subroutine
463 where the invocant is either a class or class instance. Describing a
464 routine requires at least three blocks, i.e. routine $name, signature
465 $name, and example-1 $name. The routine block should contain a
466 description of the routine and its purpose. The signature block should
467 contain a routine signature in the form of $signature : $return_type,
468 where $signature is a valid typed signature and $return_type is any
469 valid Type::Tiny expression. The example-$number block is a repeatable
470 block, and at least one block must exist when documenting a routine.
471 The example-$number block should contain valid Perl code and return a
472 value. The block may contain a "magic" comment in the form of given:
473 synopsis or given: example-$number $name which if present will include
474 the given code example(s) with the evaluation of the current block.
475 Each routine is tested and must be recognized to exist by the main
476 package.
477
478 types
479
480 =type Path
481
482 Path
483
484 =type-parent Path
485
486 Object
487
488 =type-library Path
489
490 Path::Types
491
492 =type-composite Path
493
494 InstanceOf["Path::Find"]
495
496 =type-coercion-1 Path
497
498 # can coerce from Str
499
500 './path/to/file'
501
502 =type-example-1 Path
503
504 require Path::Find;
505
506 Path::Find::path('./path/to/file')
507
508 =cut
509
510 When developing Perl programs, or type libraries, that use Type::Tiny
511 based type constraints, testing and documenting custom type constraints
512 is often overlooked. Describing a custom type constraint requires at
513 least two blocks, i.e. type $name and type-library $name. While it's
514 not strictly required, it's a good idea to also include at least one
515 type-example-1 $name. The optional type-parent block should contain the
516 name of the parent type. The type-composite block should contain a type
517 expression that represents the derived type. The type-coercion-$number
518 block is a repeatable block which is used to validate type coercion.
519 The type-coercion-$number block should contain valid Perl code and
520 return the value to be coerced. The type-example-$number block is a
521 repeatable block, and it's a good idea to have at least one block must
522 exist when documenting a type. The type-example-$number block should
523 contain valid Perl code and return a value. Each type is tested and
524 must be recognized to exist within the package specified by the
525 type-library block.
526
527AUTOMATION
528
529 $test->standard;
530
531 This is the equivalent of writing:
532
533 $test->package;
534 $test->document;
535 $test->libraries;
536 $test->inherits;
537 $test->attributes;
538 $test->methods;
539 $test->routines;
540 $test->functions;
541 $test->types;
542
543 This framework provides a set of automated subtests based on the
544 package specification, but not everything can be automated so it also
545 provides you with powerful hooks into the framework for manual testing.
546
547 my $subtests = $test->subtests;
548
549 $subtests->synopsis(sub {
550 my ($tryable) = @_;
551
552 ok my $result = $tryable->result, 'result ok';
553
554 $result; # for automated testing after the callback
555 });
556
557 The code examples documented can be automatically evaluated (evaled)
558 and returned using a callback you provide for further testing. Because
559 the code examples are returned as Test::Auto::Try objects (see
560 Data::Object::Try), this makes capturing and testing exceptions simple,
561 for example:
562
563 my $subtests = $test->subtests;
564
565 $subtests->synopsis(sub {
566 my ($tryable) = @_;
567
568 # catch exception thrown by the synopsis
569 $tryable->catch('Path::Find::Error', sub {
570 return $_[0];
571 });
572 # test the exception
573 ok my $result = $tryable->result, 'result ok';
574 ok $result->isa('Path::Find::Error'), 'exception caught';
575
576 $result;
577 });
578
579 Additionally, another manual testing hook (with some automation) is the
580 example method. This hook evaluates (evals) a given example and returns
581 the result as a Test::Auto::Try object (see Data::Object::Try). The
582 first argument is the example ID (or number), for example:
583
584 my $subtests = $test->subtests;
585
586 $subtests->example(-1, 'children', 'method', sub {
587 my ($tryable) = @_;
588
589 ok my $result = $tryable->result, 'result ok';
590
591 $result; # for automated testing after the callback
592 });
593
594 Finally, the lesser-used but useful manual testing hook is the scenario
595 method. This hook evaluates (evals) a documented scenario and returns
596 the result as a Test::Auto::Try object (see Data::Object::Try), for
597 example:
598
599 my $subtests = $test->subtests;
600
601 $subtests->scenario('export-path-make', sub {
602 my ($tryable) = @_;
603
604 ok my $result = $tryable->result, 'result ok';
605
606 $result; # for automated testing after the callback
607 });
608
609 The test automation and document generation enabled through this
610 framework makes it easy to maintain source/test/documentation parity.
611 This also increases reusability and reduces the need for complicated
612 state and test setup.
613
614AUTHOR
615
616 Al Newkirk, awncorp@cpan.org
617
618LICENSE
619
620 Copyright (C) 2011-2019, Al Newkirk, et al.
621
622 This is free software; you can redistribute it and/or modify it under
623 the terms of the The Apache License, Version 2.0, as elucidated in the
624 "license file"
625 <https://github.com/iamalnewkirk/test-auto/blob/master/LICENSE>.
626
627PROJECT
628
629 Wiki <https://github.com/iamalnewkirk/test-auto/wiki>
630
631 Project <https://github.com/iamalnewkirk/test-auto>
632
633 Initiatives <https://github.com/iamalnewkirk/test-auto/projects>
634
635 Milestones <https://github.com/iamalnewkirk/test-auto/milestones>
636
637 Issues <https://github.com/iamalnewkirk/test-auto/issues>
638
639
README.md
1# NAME
2
3Test::Auto - Test Automation
4
5# ABSTRACT
6
7Test Automation, Docs Generation
8
9# SYNOPSIS
10
11 #!/usr/bin/env perl
12
13 use Test::Auto;
14 use Test::More;
15
16 my $test = Test::Auto->new(
17 't/Test_Auto.t'
18 );
19
20 # automation
21
22 # my $subtests = $test->subtests->standard;
23
24 # ...
25
26 # done_testing;
27
28# DESCRIPTION
29
30This package aims to provide, a standard for documenting Perl 5 software
31projects, a framework writing tests, test automation, and documentation
32generation.
33
34# REASONING
35
36This framework lets you write documentation in test files using pod-like
37comment blocks. By using a particular set of comment blocks (the specification)
38this framework can run certain kinds of tests automatically. For example, we
39can automatically ensure that the package the test is associated with is
40loadable, that the test file comment blocks meet the specification, that any
41super-classes or libraries are loadable, and that the functions, methods, and
42routines are properly documented.
43
44# LIBRARIES
45
46This package uses type constraints from:
47
48[Test::Auto::Types](https://metacpan.org/pod/Test::Auto::Types)
49
50# SCENARIOS
51
52This package supports the following scenarios:
53
54## exports
55
56 use Test::Auto;
57 use Test::More;
58
59 my $subtests = testauto 't/Test_Auto.t';
60
61 # automation
62
63 # $subtests->standard;
64
65 # ...
66
67 # done_testing;
68
69This package automatically exports the `testauto` function which uses the
70"current file" as the automated testing source.
71
72# ATTRIBUTES
73
74This package has the following attributes:
75
76## data
77
78 data(Data)
79
80This attribute is read-only, accepts `(Data)` values, and is optional.
81
82## file
83
84 file(Str)
85
86This attribute is read-only, accepts `(Str)` values, and is required.
87
88# FUNCTIONS
89
90This package implements the following functions:
91
92## testauto
93
94 testauto(Str $file) : Subtests
95
96This function is exported automatically and returns a [Test::Auto::Subtests](https://metacpan.org/pod/Test::Auto::Subtests)
97object for the test file given.
98
99- testauto example #1
100
101 # given: synopsis
102
103 my $subtests = testauto 't/Test_Auto.t';
104
105# METHODS
106
107This package implements the following methods:
108
109## document
110
111 document() : Document
112
113This method returns a [Test::Auto::Document](https://metacpan.org/pod/Test::Auto::Document) object.
114
115- document example #1
116
117 # given: synopsis
118
119 my $document = $test->document;
120
121## parser
122
123 parser() : Parser
124
125This method returns a [Test::Auto::Parser](https://metacpan.org/pod/Test::Auto::Parser) object.
126
127- parser example #1
128
129 # given: synopsis
130
131 my $parser = $test->parser;
132
133## subtests
134
135 subtests() : Subtests
136
137This method returns a [Test::Auto::Subtests](https://metacpan.org/pod/Test::Auto::Subtests) object.
138
139- subtests example #1
140
141 # given: synopsis
142
143 my $subtests = $test->subtests;
144
145# SPECIFICATION
146
147 # [required]
148
149 =name
150 =abstract
151 =tagline
152 =includes
153 =synopsis
154 =description
155
156 # [optional]
157
158 =libraries
159 =inherits
160 =integrates
161 =attributes
162
163 # [repeatable; optional]
164
165 =scenario $name
166 =example $name
167
168 # [repeatable; optional]
169
170 =method $name
171 =signature $name
172 =example-$number $name # [repeatable]
173
174 # [repeatable; optional]
175
176 =function $name
177 =signature $name
178 =example-$number $name # [repeatable]
179
180 # [repeatable; optional]
181
182 =routine $name
183 =signature $name
184 =example-$number $name # [repeatable]
185
186 # [repeatable; optional]
187
188 =type $name
189 =type-library $name
190 =type-composite $name # [optional]
191 =type-parent $name # [optional]
192 =type-coercion-$number $name # [optional]
193 =type-example-$number $name # [repeatable]
194
195The specification is designed to accommodate typical package declarations. It
196is used by the parser to provide the content used in the test automation and
197document generation. Note: when code blocks are evaluated _"redefined"_
198warnings are now automatically disabled.
199
200## name
201
202 =name
203
204 Path::Find
205
206 =cut
207
208The `name` block should contain the package name. This is tested for
209loadability.
210
211## tagline
212
213 =tagline
214
215 Path Finder
216
217 =cut
218
219The `tagline` block should contain a tagline for the package. This is optional
220but if present is concatenated with the `name` during POD generation.
221
222## abstract
223
224 =abstract
225
226 Find Paths using Heuristics
227
228 =cut
229
230The `abstract` block should contain a subtitle describing the package. This is
231tested for existence.
232
233## includes
234
235 =includes
236
237 function: path
238 method: children
239 method: siblings
240 method: new
241
242 =cut
243
244The `includes` block should contain a list of `function`, `method`, and/or
245`routine` names in the format of `$type: $name`. Empty lines are ignored.
246This is tested for existence. Each function, method, and/or routine is tested
247to be documented properly. Also, the package must recognize that each exists.
248
249## synopsis
250
251 =synopsis
252
253 use Path::Find 'path';
254
255 my $path = path; # get path using cwd
256
257 =cut
258
259The `synopsis` block should contain the normative usage of the package. This
260is tested for existence. This block should be written in a way that allows it
261to be evaled successfully and should return a value.
262
263## description
264
265 =description
266
267 interdum posuere lorem ipsum dolor sit amet consectetur adipiscing elit duis
268 tristique sollicitudin nibh sit amet
269
270 =cut
271
272The `description` block should contain a thorough explanation of the purpose
273of the package. This is tested for existence.
274
275## libraries
276
277 =libraries
278
279 Types::Standard
280 Types::TypeTiny
281
282 =cut
283
284The `libraries` block should contain a list of packages, each of which is
285itself a [Type::Library](https://metacpan.org/pod/Type::Library). These packages are tested for loadability, and to
286ensure they are type library classes.
287
288## inherits
289
290 =inherits
291
292 Path::Tiny
293
294 =cut
295
296The `inherits` block should contain a list of parent packages. These packages
297are tested for loadability.
298
299## integrates
300
301 =integrates
302
303 Path::Find::Upable
304 Path::Find::Downable
305
306 =cut
307
308The `integrates` block should contain a list of packages that are involved in
309the behavior of the main package. These packages are not automatically tested.
310
311## scenarios
312
313 =scenario export-path-make
314
315 quisque egestas diam in arcu cursus euismod quis viverra nibh
316
317 =example export-path-make
318
319 # given: synopsis
320
321 package main;
322
323 use Path::Find 'path_make';
324
325 path_make 'relpath/to/file';
326
327 =cut
328
329There are situation where a package can be configured in different ways,
330especially where it exists without functions, methods or routines for the
331purpose of configuring the environment. The scenario directive can be used to
332automate testing and documenting package usages and configurations.Describing a
333scenario requires two blocks, i.e. `scenario $name` and `example $name`. The
334`scenario` block should contain a description of the scenario and its purpose.
335The `example` block must exist when documenting a method and should contain
336valid Perl code and return a value. The block may contain a "magic" comment in
337the form of `given: synopsis` or `given: example $name` which if present will
338include the given code example(s) with the evaluation of the current block.
339Each scenario is tested and must be recognized to exist by the main package.
340
341## attributes
342
343 =attributes
344
345 cwd: ro, req, Object
346
347 =cut
348
349The `attributes` block should contain a list of package attributes in the form
350of `$name: $is, $presence, $type`, where `$is` should be `ro` (read-only) or
351`rw` (read-wire), and `$presence` should be `req` (required) or `opt`
352(optional), and `$type` can be any valid [Type::Tiny](https://metacpan.org/pod/Type::Tiny) expression. Each
353attribute declaration must be recognized to exist by the main package and have
354a type which is recognized by one of the declared type libraries.
355
356## methods
357
358 =method children
359
360 quis viverra nibh cras pulvinar mattis nunc sed blandit libero volutpat
361
362 =signature children
363
364 children() : [Object]
365
366 =example-1 children
367
368 # given: synopsis
369
370 my $children = $path->children;
371
372 =example-2 children
373
374 # given: synopsis
375
376 my $filtered = $path->children(qr/lib/);
377
378 =cut
379
380Describing a method requires at least three blocks, i.e. `method $name`,
381`signature $name`, and `example-1 $name`. The `method` block should contain
382a description of the method and its purpose. The `signature` block should
383contain a method signature in the form of `$signature : $return_type`, where
384`$signature` is a valid typed signature and `$return_type` is any valid
385[Type::Tiny](https://metacpan.org/pod/Type::Tiny) expression. The `example-$number` block is a repeatable block,
386and at least one block must exist when documenting a method. The
387`example-$number` block should contain valid Perl code and return a value. The
388block may contain a "magic" comment in the form of `given: synopsis` or
389`given: example-$number $name` which if present will include the given code
390example(s) with the evaluation of the current block. Each method is tested and
391must be recognized to exist by the main package.
392
393## functions
394
395 =function path
396
397 lectus quam id leo in vitae turpis massa sed elementum tempus egestas
398
399 =signature children
400
401 path() : Object
402
403 =example-1 path
404
405 package Test::Path::Find;
406
407 use Path::Find;
408
409 my $path = path;
410
411 =cut
412
413Describing a function requires at least three blocks, i.e. `function $name`,
414`signature $name`, and `example-1 $name`. The `function` block should
415contain a description of the function and its purpose. The `signature` block
416should contain a function signature in the form of `$signature :
417$return_type`, where `$signature` is a valid typed signature and
418`$return_type` is any valid [Type::Tiny](https://metacpan.org/pod/Type::Tiny) expression. The `example-$number`
419block is a repeatable block, and at least one block must exist when documenting
420a function. The `example-$number` block should contain valid Perl code and
421return a value. The block may contain a "magic" comment in the form of `given:
422synopsis` or `given: example-$number $name` which if present will include the
423given code example(s) with the evaluation of the current block. Each function
424is tested and must be recognized to exist by the main package.
425
426## routines
427
428 =routine algorithms
429
430 sed sed risus pretium quam vulputate dignissim suspendisse in est ante
431
432 =signature algorithms
433
434 algorithms() : Object
435
436 =example-1 algorithms
437
438 # given: synopsis
439
440 $path->algorithms
441
442 =example-2 algorithms
443
444 package Test::Path::Find;
445
446 use Path::Find;
447
448 Path::Find->algorithms;
449
450 =cut
451
452Typically, a Perl subroutine is declared as a function or a method. Rarely, but
453sometimes necessary, you will need to describe a subroutine where the invocant
454is either a class or class instance. Describing a routine requires at least
455three blocks, i.e. `routine $name`, `signature $name`, and `example-1
456$name`. The `routine` block should contain a description of the routine and
457its purpose. The `signature` block should contain a routine signature in the
458form of `$signature : $return_type`, where `$signature` is a valid typed
459signature and `$return_type` is any valid [Type::Tiny](https://metacpan.org/pod/Type::Tiny) expression. The
460`example-$number` block is a repeatable block, and at least one block must
461exist when documenting a routine. The `example-$number` block should contain
462valid Perl code and return a value. The block may contain a "magic" comment in
463the form of `given: synopsis` or `given: example-$number $name` which if
464present will include the given code example(s) with the evaluation of the
465current block. Each routine is tested and must be recognized to exist by the
466main package.
467
468## types
469
470 =type Path
471
472 Path
473
474 =type-parent Path
475
476 Object
477
478 =type-library Path
479
480 Path::Types
481
482 =type-composite Path
483
484 InstanceOf["Path::Find"]
485
486 =type-coercion-1 Path
487
488 # can coerce from Str
489
490 './path/to/file'
491
492 =type-example-1 Path
493
494 require Path::Find;
495
496 Path::Find::path('./path/to/file')
497
498 =cut
499
500When developing Perl programs, or type libraries, that use [Type::Tiny](https://metacpan.org/pod/Type::Tiny) based
501type constraints, testing and documenting custom type constraints is often
502overlooked. Describing a custom type constraint requires at least two blocks,
503i.e. `type $name` and `type-library $name`. While it's not strictly required,
504it's a good idea to also include at least one `type-example-1 $name`. The
505optional `type-parent` block should contain the name of the parent type. The
506`type-composite` block should contain a type expression that represents the
507derived type. The `type-coercion-$number` block is a repeatable block which
508is used to validate type coercion. The `type-coercion-$number` block should
509contain valid Perl code and return the value to be coerced. The
510`type-example-$number` block is a repeatable block, and it's a good idea to
511have at least one block must exist when documenting a type. The
512`type-example-$number` block should contain valid Perl code and return a
513value. Each type is tested and must be recognized to exist within the package
514specified by the `type-library` block.
515
516# AUTOMATION
517
518 $test->standard;
519
520This is the equivalent of writing:
521
522 $test->package;
523 $test->document;
524 $test->libraries;
525 $test->inherits;
526 $test->attributes;
527 $test->methods;
528 $test->routines;
529 $test->functions;
530 $test->types;
531
532This framework provides a set of automated subtests based on the package
533specification, but not everything can be automated so it also provides you with
534powerful hooks into the framework for manual testing.
535
536 my $subtests = $test->subtests;
537
538 $subtests->synopsis(sub {
539 my ($tryable) = @_;
540
541 ok my $result = $tryable->result, 'result ok';
542
543 $result; # for automated testing after the callback
544 });
545
546The code examples documented can be automatically evaluated (evaled) and
547returned using a callback you provide for further testing. Because the code
548examples are returned as `Test::Auto::Try` objects (see [Data::Object::Try](https://metacpan.org/pod/Data::Object::Try)),
549this makes capturing and testing exceptions simple, for example:
550
551 my $subtests = $test->subtests;
552
553 $subtests->synopsis(sub {
554 my ($tryable) = @_;
555
556 # catch exception thrown by the synopsis
557 $tryable->catch('Path::Find::Error', sub {
558 return $_[0];
559 });
560 # test the exception
561 ok my $result = $tryable->result, 'result ok';
562 ok $result->isa('Path::Find::Error'), 'exception caught';
563
564 $result;
565 });
566
567Additionally, another manual testing hook (with some automation) is the
568`example` method. This hook evaluates (evals) a given example and returns the
569result as a `Test::Auto::Try` object (see [Data::Object::Try](https://metacpan.org/pod/Data::Object::Try)). The first
570argument is the example ID (or number), for example:
571
572 my $subtests = $test->subtests;
573
574 $subtests->example(-1, 'children', 'method', sub {
575 my ($tryable) = @_;
576
577 ok my $result = $tryable->result, 'result ok';
578
579 $result; # for automated testing after the callback
580 });
581
582Finally, the lesser-used but useful manual testing hook is the `scenario`
583method. This hook evaluates (evals) a documented scenario and returns the
584result as a `Test::Auto::Try` object (see [Data::Object::Try](https://metacpan.org/pod/Data::Object::Try)), for example:
585
586 my $subtests = $test->subtests;
587
588 $subtests->scenario('export-path-make', sub {
589 my ($tryable) = @_;
590
591 ok my $result = $tryable->result, 'result ok';
592
593 $result; # for automated testing after the callback
594 });
595
596The test automation and document generation enabled through this framework
597makes it easy to maintain source/test/documentation parity. This also
598increases reusability and reduces the need for complicated state and test setup.
599
600# AUTHOR
601
602Al Newkirk, `awncorp@cpan.org`
603
604# LICENSE
605
606Copyright (C) 2011-2019, Al Newkirk, et al.
607
608This is free software; you can redistribute it and/or modify it under the terms
609of the The Apache License, Version 2.0, as elucidated in the
610["license file"](https://github.com/iamalnewkirk/test-auto/blob/master/LICENSE).
611
612# PROJECT
613
614[Wiki](https://github.com/iamalnewkirk/test-auto/wiki)
615
616[Project](https://github.com/iamalnewkirk/test-auto)
617
618[Initiatives](https://github.com/iamalnewkirk/test-auto/projects)
619
620[Milestones](https://github.com/iamalnewkirk/test-auto/milestones)
621
622[Issues](https://github.com/iamalnewkirk/test-auto/issues)
623