thatsus/test-api-protect

Avoid hitting third party API's by forcing their client classes to be mocked in tests

v1.0.1 2018-09-17 19:06 UTC

This package is not auto-updated.

Last update: 2024-04-28 03:03:57 UTC


README

Avoid hitting third party API's by forcing their client classes to be mocked in Laravel and Lumen tests.

Protect any classes in Laravel tests

Install

composer require thatsus/test-api-protect

Add to TestCase

  • Use the ProtectClasses trait,
  • list the $protected_classes, and
  • call protectClasses in the setUp.
use ThatsUs\ProtectClasses;

class TestCase extends \Illuminate\Foundation\Testing\TestCase
{
    
    use ProtectClasses;

    protected $protected_classes = [
        \Facebook\Facebook::class,
        \GuzzleHttp\Client::class,
        \App\SomeExpensiveClass::class,
    ];

    public function setUp()
    {
        parent::setUp();

        $this->protectClasses();
    }

    ...
}

Make Mistakes with Confidence

Imagine you forgot that this Innocent class uses \App\SomeExpensiveClass.

class InnocentTest extends TestCase
{

    public function testInnocentMethod()
    {
        $good_guy = new Innocent();
        $this->assertTrue($good_guy->everythingIsFine());
    }
}
class Innocent 
{

    public function everythingIsFine()
    {
        app('App\SomeExpensiveClass')->doThing();
        return true;
    }
}

Now you get this error.

PHPUnit 5.7.16 by Sebastian Bergmann and contributors.

..E..                                                               5 / 5 (100%)

Time: 152 ms, Memory: 14.00MB

There was 1 error:

1) ThatsUs\InnocentTest::testInnocentMethod
Exception: The App\SomeExpensiveClass instance is protected for tests. Setup 
a mock object using App::bind('App\SomeExpensiveClass', Closure). Method 
called: doThing.

./vendor/ThatsUs/FakeProtectedClass.php:21
./src/Innocent.php:10
./tests/InnocentTest.php:15

ERRORS!
Tests: 5, Assertions: 6, Errors: 1.

You just saved yourself from doing something dangerous! Pat yourself on the back and go edit that test file.

use Illuminate\Support\Facades\App;
use Mockery;

class InnocentTest extends TestCase
{

    public function testInnocentMethod()
    {
        App::bind(\App\SomeExpensiveClass::class, function () {
            $mock = Mockery::mock(\App\SomeExpensiveClass::class);
            $mock->shouldReceive('doThing')->once();
            return $mock;
        });

        $good_guy = new Innocent();
        $this->assertTrue($good_guy->everythingIsFine());
    }
}

No Trouble

If the code under test only instantiates a class without calling any methods on it, no exception is thrown.

Contribution

If you find a bug or want to contribute to the code or documentation, you can help by submitting an issue or a pull request.

License

MIT