Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,35 @@ This will test `my_function` using the `Generator::strings()` generator.
You can also register your own Generators using the
`Annotation::register($type, $generator)` method.

## PHPUnit

To use php-quickcheck with PHPUnit, the assertion `\QCheck\PHPUnit\Constraint\Prop` is provided.
It provides a static constructor method `Prop::check`. Similar to `Quick::check`, the method takes the size and allows also passing options if needed.

```php
public function testStringsAreLessThanTenChars()
{
$property = Gen::forAll([Gen::strings()], function ($s): bool {
return 10 > strlen($s);
});
$this->assertThat($property, Prop::check(50)); // will fail
}
```
The assertion will delegate to `Quick::check($size, $property)`, and if the function returns anything but `true`, it will display a formatted failure description.

```
Failed asserting that property is true.
Tests runs: 16, failing size: 15, seed: 1578486446175, smallest shrunk value(s):
array (
0 => <failed shrunk value>,
)
```

If an exception is thrown or a PHPUnit assertion fails, the message will be included in the output.

To reproduce a test result the displayed seed can be passed via `Prop::check($size, ['seed' => 1578486446175])`.


## Project Status

PhpQuickCheck is highly experimental and in its very early stages. Only
Expand Down
69 changes: 69 additions & 0 deletions src/QCheck/PHPUnit/Constraint/Prop.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

namespace QCheck\PHPUnit\Constraint;

use PHPUnit\Framework\Constraint\Constraint;
use QCheck\Quick;

class Prop extends Constraint
{
/**
* @var int
*/
private $size;

/**
* @var array
*/
private $opts;

public function __construct(int $n, array $opts = [])
{
$this->size = $n;
$this->opts = $opts;
}

public static function check($n = 100, array $opts = [])
{
return new self($n, $opts);
}

public function evaluate($prop, string $description = '', bool $returnResult = false)
{
$result = Quick::check($this->size, $prop, $this->opts);
return parent::evaluate($result, $description, $returnResult);
}

protected function matches($other): bool
{
return @$other['result'] === true;
}

public function toString(): string
{
return 'property is true';
}

protected function failureDescription($other): string
{
return $this->toString();
}

protected function additionalFailureDescription($other): string
{
return sprintf(
"%sTests runs: %d, failing size: %d, seed: %s, smallest shrunk value(s):\n%s",
$this->extractExceptionMessage($other['result']),
$other['num_tests'],
$other['failing_size'],
$other['seed'],
var_export($other['shrunk']['smallest'], true)
);
}

private function extractExceptionMessage($result): string
{
return $result instanceof \Exception ? $result->getMessage() . "\n" : '';
}

}