Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
* develop:
  only Set::values() needs to be declared internal
  expose a seeder
  fix typo
  • Loading branch information
Baptouuuu committed May 2, 2020
2 parents a71853b + b3f50de commit cc0c975
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 4 deletions.
8 changes: 5 additions & 3 deletions README.md
Expand Up @@ -80,7 +80,7 @@ class CounterTest extends \PHPUnit\Framework\TestCase
{
use BlackBox;

public function testCounterValueIsAlwaysHigherAfterCoutningUp()
public function testCounterValueIsAlwaysHigherAfterCountingUp()
{
$this
->forAll(
Expand All @@ -104,7 +104,7 @@ By default the library supports the shrinking of data to help you find the small

### Stateful testing

When we write tests we tend to focus on evaluating the behaviour when doing one action (like in our counter example above). This technique help us cover most of our code, but when we deal we stateful systems (such as a counter, an entity or a daemon) it becomes harder to make sure all succession of mutations will always result in a coherent new state.
When we write tests we tend to focus on evaluating the behaviour when doing one action (like in our counter example above). This technique help us cover most of our code, but when we deal with stateful systems (such as a counter, an entity or a daemon) it becomes harder to make sure all succession of mutations will always result in a coherent new state.

Once again Property Based Testing can help us improve the coverage of behaviours. Instead of describing the initial test to the framework and manually do one action, we describe to the framework all the properties that our system must hold and the framework will try to find a succession of actions that will break our properties.

Expand All @@ -126,7 +126,7 @@ final class CountingUpAlwaysEndInAHigherCount implements Property
return $counter->current() < 100; // since upper bound is 100
}

public function ensureHelBy(object $counter): object
public function ensureHeldBy(object $counter): object
{
$initial = $counter->current();
$counter->up();
Expand Down Expand Up @@ -172,6 +172,8 @@ The above example would generate multiple scenarii of counting up and down (it t

**Note 2**: this example was taken from an article by [Johannes Link](https://twitter.com/johanneslink) on [Model-based Testing](https://johanneslink.net/model-based-testing/).

**Note 3**: to help randomize your properties you may want to inject some data in them. If we reuse the example property `RaiseValueAction` from the [article by Johannes Link](https://johanneslink.net/model-based-testing/) we could seed it with `new RaiseValueAction($this->seeder()(Set\Integers::between(1, 99)))`, this example would instantiate the property with an `int` between `1` and `99` as argument. Note that the seed is done once for the whole test unlike the values injected in the `then` callback that change at every call.

## Configuration

### Set size
Expand Down
8 changes: 8 additions & 0 deletions src/PHPUnit/BlackBox.php
Expand Up @@ -63,4 +63,12 @@ protected function forAll(Set $first, Set ...$sets): Scenario

return $scenario;
}

/**
* Use the seeder to generate random values to initiate your properties
*/
protected function seeder(): Seeder
{
return new Seeder(new RandomInt);
}
}
31 changes: 31 additions & 0 deletions src/PHPUnit/Seeder.php
@@ -0,0 +1,31 @@
<?php
declare(strict_types = 1);

namespace Innmind\BlackBox\PHPUnit;

use Innmind\BlackBox\{
Set,
Random,
};

final class Seeder
{
private Random $random;

public function __construct(Random $random)
{
$this->random = $random;
}

/**
* @template T
*
* @param Set<T> $set
*
* @return T
*/
public function __invoke(Set $set)
{
return $set->values($this->random)->current()->unwrap();
}
}
3 changes: 2 additions & 1 deletion src/Set.php
Expand Up @@ -6,7 +6,6 @@
use Innmind\BlackBox\Set\Value;

/**
* @internal End users mustn't create implementations of this interface (BC breaks may be introduced)
* @template T The type of data being generated
*/
interface Set
Expand All @@ -24,6 +23,8 @@ public function take(int $size): self;
public function filter(callable $predicate): self;

/**
* @internal End users mustn't use this method directly (BC breaks may be introduced)
*
* @return \Generator<Value<T>>
*/
public function values(Random $rand): \Generator;
Expand Down
6 changes: 6 additions & 0 deletions tests/PHPUnit/BlackBoxTest.php
Expand Up @@ -5,6 +5,7 @@

use Innmind\BlackBox\{
PHPUnit\BlackBox,
PHPUnit\Seeder,
Set,
};
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -49,4 +50,9 @@ public function testDoesntFailWhenTheExceptionIsExpected()
throw $exception;
});
}

public function testSeederIsAccessible()
{
$this->assertInstanceOf(Seeder::class, $this->seeder());
}
}
40 changes: 40 additions & 0 deletions tests/PHPUnit/SeederTest.php
@@ -0,0 +1,40 @@
<?php
declare(strict_types = 1);

namespace Tests\Innmind\BlackBox\PHPUnit;

use Innmind\BlackBox\{
PHPUnit\Seeder,
Random\RandomInt,
};
use PHPUnit\Framework\TestCase;
use Innmind\BlackBox\{
PHPUnit\BlackBox,
Set,
};

class SeederTest extends TestCase
{
use BlackBox;

public function testAlwaysReturnADifferentValue()
{
$this
->forAll(Set\Elements::of(
Set\Chars::any(),
Set\Email::any(),
Set\Strings::any(),
Set\UnsafeStrings::any(),
Set\Uuid::any(),
))
->then(function($set) {
$seeder = new Seeder(new RandomInt);

$this->assertIsString($seeder($set));
$this->assertNotSame(
$seeder($set),
$seeder($set),
);
});
}
}

0 comments on commit cc0c975

Please sign in to comment.