How to Instantly Migrate Nette\Tester to PHPUnit

This post was updated at November 2020

Switch from deprecated --set option to rector.php config.


We had 🍺 after PHP meetup in Prague and Tomas asked me:
"We don't use Nette, but we still have many tests in Tester. Can Rector migrate them to PHPUnit?"
"Hold my 🍺"

In the last post we looked on instant migration of PhpSpec to PHPUnit.

PhpSpec has a different architecture than PHPUnit - e.g.

This has a huge influence on the code, so it took a week to cover these differences in migration path.

How does Tester compare to PHPUnit?

In the last post we looked at absolute downloads and trends of 3 PHP unit test frameworks:

Putting numbers and trends aside - this is about your needs. Do you need to change from Doctrine to Eloquent? From Symfony 4.2 to Laravel 5.8? From Symfony to Nette? Go for it, Rector will help you with the boring PHP work you'd love to skip.

The guy in the pub that night needed this, so... challenge accepted!

Single Test Case

Luckily, Tester and PHPUnit are like twins:

So all we need to do is rename a few methods? There are still a few gotchas:

Luckily, last 2 operations are subtractions, so we can just remove them.

And the Result?

 <?php

 namespace App\Tests;

 use App\Entity\SomeObject;
-use Tester\Assert;
-use Tester\TestCase;

-require_once __DIR__ . '/bootstrap.php';

-class ExpensiveObjectTest extends TestCase
+class ExpensiveObjectTest extends \PHPUnit\Framework\TestCase
 {
     public function testSwitches()
     {
-        Assert::false(5);
+        $this->assertFalse(5);

-        Assert::falsey('value', 'some messsage');
+        $this->assertFalse((bool) 'value', 'some messsage');

-        Assert::truthy(true);
+        $this->assertTrue(true);
     }

     public function testTypes()
     {
         $value = 'x';
-        Assert::type('array', $value);
+        $this->assertIsArray($value);

-        Assert::type(SomeObject::class, $value);
+        $this->assertInstanceOf(SomeObject::class, $value);
     }

     public function testException()
     {
         $someObject = new SomeObject;
-        Assert::exception(function () use ($someObject) {
-            $someObject->setPrice('twenty dollars');
-        }, InvalidArgumentException::class, 'Price should be string, you know');
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Price should be string, you know');
+        $someObject->setPrice('twenty dollars');
     }

+    /**
+     * @doesNotPerformAssertions
+     */
     public function testNoError()
     {
-        Assert::noError(function () {
-             new SomeObject(25)
-        });
+        new SomeObject(25);
     }
 }

-(new ExpensiveObjectTest())->run();

How to Instantly Migrate from Nette\Tester to PHPUnit?

  1. Install Rector
composer require rector/rector --dev
  1. Add rector.php config:
// rector.php
use Rector\Core\Configuration\Option;
use Rector\Set\ValueObject\SetList;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
    $parameters = $containerConfigurator->parameters();
    $parameters->set(Option::SETS, [SetList::NETTE_TESTER_TO_PHPUNIT]);
};
  1. Run it on /tests directory
vendor/bin/rector process tests

Then take few minutes to polish the details that Rectors missed and send the PR to your project


Happy coding!