gentry / gentry
PHP unit test generation tools
Requires
- php: >=8.1
- monolyth/cliff: ^0.7.0
- monomelodies/kingconf: ^1.1.0
- monomelodies/reflex: ^0.3.0
- simoneast/simple-ansi-colors: ^1.0
- twig/twig: ^2.0|^3.0
Requires (Dev)
- toast/unit: ^2.1
- dev-master
- 0.16.12
- 0.16.11
- 0.16.10
- 0.16.9
- 0.16.8
- 0.16.7
- 0.16.6
- 0.16.5
- 0.16.4
- 0.16.3
- 0.16.2
- 0.16.1
- 0.16.0
- 0.15.1
- 0.15.0
- 0.14.5
- 0.14.4
- 0.14.3
- 0.14.2
- 0.14.1
- 0.14.0
- 0.13.16
- 0.13.15
- 0.13.14
- 0.13.13
- 0.13.12
- 0.13.11
- 0.13.10
- 0.13.9
- 0.13.8
- 0.13.7
- 0.13.6
- 0.13.5
- 0.13.4
- 0.13.3
- 0.13.2
- 0.13.1
- 0.13.0
- 0.12.9
- 0.12.8
- 0.12.7
- 0.12.6
- 0.12.5
- 0.12.4
- 0.12.3
- 0.12.2
- 0.12.1
- 0.12.0
- 0.11.8
- 0.11.7
- 0.11.6
- 0.11.5
- 0.11.4
- 0.11.3
- 0.11.2
- 0.11.1
- 0.11.0
- 0.10.5
- 0.10.4
- 0.10.3
- 0.10.2
- 0.10.1
- 0.10.0
- 0.9.0
- 0.8.5
- 0.8.4
- 0.8.3
- 0.8.2
- 0.8.1
- 0.8.0
- 0.7.7
- 0.7.6
- 0.7.5
- 0.7.4
- 0.7.3
- 0.7.2
- 0.7.1
- 0.7.0
- 0.6.2
- 0.6.1
- 0.6.0
- 0.5.3
- 0.5.2
- 0.5.1
- 0.5.0
- 0.4.1
- 0.4.0
- 0.3.9
- 0.3.8
- 0.3.7
- 0.3.6
- 0.3.5
- 0.3.4
- 0.3.3
- 0.3.2
- 0.3.1
- 0.3.0
- 0.2.0
- 0.1.9
- 0.1.8
- 0.1.7
- 0.1.6
- 0.1.5
- 0.1.4
- 0.1.3
- 0.1.2
- 0.1.1
- 0.1.0
- dev-dependabot/composer/twig/twig-3.11.2
- dev-develop
- dev-testing-framework
This package is auto-updated.
Last update: 2025-04-26 15:38:36 UTC
README
Test generation tools for PHP8+.
Good programmers are lazy, but unfortunately that means that stuff like writing tests (boooooring) is often skipped. Please don't; it's important and oh so handy once you have them in place.
Gentry was designed to make writing tests so easy even the worst slacker will bother, and to alleviate writing boilerplate code by generating skeletons for you.
Installation
composer require --dev gentry/gentry
You can now run vendor/bin/gentry
.
Configuration
Create a Gentry.json
file in the root of your project. It accepts the
following options:
{ "src": "/path/to/src", "test": "/path/to/testrunner/executable", "ignore": "some.*?regex", "bootstrap": "/path/to/file", "generator": "Fully\\Qualified\\Namespace", "output": "/path/to/directory", "namespace": "Your\\Preferred\\Namespace" }
string|array src
Path(s) to your source files. Can be either absolute or relative to project
root - hence"/path/to/src"
could be simplified to just "src"
. If you have
multiple source paths you may define an array of strings.
Directories are recursed automatically.
string test
The command you use to run your (unit)tests for PHP normally (e.g.
vendor/bin/phpunit
).
string|array ignore
(A) regular expression(s) of classnames to ignore in the "src"
path. Useful for
automatically ignoring classtypes that are hard to test, e.g. controllers. You
could also utilise this if your tests and sourcecode are mixed in the same
directory (some frameworks like that kind of thing).
string|array bootstrap
The path(s) to file(s) ("bootstrapper(s)") every piece of code in your
application needs. This is usually something that would reside in an index.php
entry point or similar file. These files are otherwise ignored by Gentry when
analysing your code and should do stuff like initialise an autoloader.
You can also pass an array of files instead of a string. They will be prepended in order.
Caution: if
bootstrap
ped files reside insidesrc
, they won't be ignored. Gentry usesrequire_once
of course, but if these files contain testable features it will try and do something sensible with them.
This isn't necessarily a bad thing; you could actually write tests that test the mock objects you use in other tests :)
string generator
The "generator" used when creating stub tests. For instance, for the
gentry/toast
plugin this would be Gentry\\Toast
. More about these plugins
below. Note that Gentry\\Toast
in this example is the namespace; by default,
the actual class should be called Generator
and extend the abstract base class
Gentry\Gentry\Generator
.
string output
The directory where generated tests will be written to. No files will be
overwritten; if a guesstimated filename already exists, it will be suffixed
with .1
(or .2
etc.).
CLI usage
Now run Gentry from the command line and see what happens:
$ vendor/bin/gentry analyze
It will complain about zero code coverage, even if you already defined a bunch of tests. Wait, wut? Well, you do need to tell Gentry what you've already written tests for.
Modifying existing tests for Gentry compatibility
In your tests, instead of simply creating/using stuff, you'll need to build a wrapped entity. Entities wrapped by Gentry are "Gentry aware".
To create wrapped entities, we use the Gentry\Gentry\Wrapper
utility class.
Wrapping objects
<?php function myTest() { // Instead of this... $foo = new Foo; // ...do this: $foo = new Gentry\Gentry\Wrapper(new Foo); // or however your testing framework asserts stuff... assert($foo->someMethod() === true); }
Try it in one of your tests and watch the code coverage increase!
All method calls and properties are proxied to the original object, so just do
whatever you wanted to do as when $foo
was actually an instance of Foo
. The
only thing you cannot do is pass it to other methods that actually expect a
Foo
. But that would be silly testing anyway; if you're testing
Bar::someOtherMethod
you're not testing Foo
, so that should be its own test
(where Bar
is wrapped instead). Keep it clean, folks!
Note: the proxying of methods/properties extends to inaccessible ones, using reflection. This is because you might want to test if some internal state was set correctly. But, ideally one would only need to test public stuff. Gentry only attempts to generate tests for public methods to begin with. If a protected or private method is called on a wrapped object, it has no effect on the tests being generated, even though Gentry internally will know about it.
Generating tests
If you'd mostly like to see what Gentry would propose to do, run the following:
$ vender/bin/gentry show
This will output all generated tests to STDOUT. Happy with what you see? Then you can run:
$ vendor/bin/gentry generate
Example using Toast
Let's show an example of generating tests for the Toast test runner (since that's what I usually choose - I wrote it, after all ;)). Gentry offers a pre-built template for this! Install it first:
composer require --dev gentry/toast
Next we configure it:
{ //... generator: "Gentry\\Toast" //... }
That's all! Well, unless you want a namespace of course, but Toast tests consist of lambdas so it's generally not needed.
The test file names are guesstimated based on the class names; you'll probably want to do some regrouping to keep things organized. But hey, at least you can copy/paste the boilerplate!
Writing custom Generators
The base Generator contains two abstract methods you must implement:
abstract protected function convertTestNameToFilename(string $name) : string; abstract protected function getTemplatePath() : string;
convertTestNameToFilename
takes the class name of the object under test, and
converts that to a filename. Subdirectories are currently not supported, in the
sense that creating them is up to you.
getTemplatePath
returns the path of your Twig templates. One template should
at least be available: template.html.twig
. Of course, you're free to split out
stuff into smaller templates using standard Twig {% extends %}
and
{% include %}
functionality. Take a look at gentry/toast
for an example.
And... that's it, really. Your template.html.twig
will receive three
variables:
namespace
: the namespace defined in the config file, ornull
.objectUnderTest
: the class name of the object under test.features
: an array of features to test (i.e., the public methods).
features
contains an array with method names as the keys, and a stdClass
with a calls
property containing an array in the following form:
<?php $this->features[$method->name]->calls[] = (object)[ 'name' => $method->name, 'parameters' => implode(', ', $arglist), 'expectedResult' => $expectedResult, 'isStatic' => $method->isStatic(), ];
Note that the parameters
key contains a string; you can just inject this
verbatim when "calling" your method in the template.
Customizing the location of the tempfile
To communicate between your tests and the Gentry command, Gentry writes results
to a tempfile. It's default location is sys_get_temp_dir().'/gentry'
, but you
may override it by specifying the tmpfile
key in your Gentry.json
. If the
path is not absolute, it will be considered relative to CWD
.