Getting Started with Orchestra Testbench for Laravel Package Development

Posted: 2018-04-01 18:08:06

The goal of this article will allow one to setup a stand alone package working with it's own tests and has access to all of the normal Laravel workflows outside of Laravel. So you can build it using the easier conventions and helpers Laravel offers.

Since my work will include database usage I will grab both packages:

composer require --dev "orchestra/testbench:<=3.5" "orchestra/database:v3.5.0"

I will setup my composer.json after this as such:

  "autoload-dev": {
    "psr-4": {
      "Tests\\": "tests/"
    }
  }

This way my classes will just have the Tests namespace.

And then add tests/TestCase.php

<?php

namespace Tests;

use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Mockery;
use AlfredNutileInc\HPClient\HubPlannerProvider;

class TestCase extends \Orchestra\Testbench\TestCase
{

    /**
     * Load any providers I am offering
    */ 
    protected function getPackageProviders($app)
    {
        return
            [
            HubPlannerProvider::class,
        ];
    }


    public function setUp()
    {
        parent::setUp();
                //I can load any local factories if I want to
        //$this->withFactories(__DIR__ . '/../database/factories');

                //make the bast path under tests folder
                $this->app->setBasePath(__DIR__ . '/../');

        //Because I use dynamic facades
        \File::makeDirectory(base_path("storage/framework/cache"), 0755, true, true);

        //I can deliver routes for testing
        //$this->app['router']->get('example', function () {
        //     return view("testing");
        //})->name('featured');

        //Load a view for testing
        //\View::addLocation(__DIR__ . '/../views');

        //$this->loadLaravelMigrations(['--database' => 'testing']);

        //Any migrations I need to bring in
        $this->loadMigrationsFrom([
            '--database' => 'testing',
            '--path' => realpath(__DIR__ . '/migrations')
        ]);

        //$output = $this->artisan('migrate', ['--database' => 'testing']);
    }


    /**
     * Setup logging
     */
    protected function getEnvironmentSetUp($app)
    {
        $app->configureMonologUsing(function ($monolog) {
            $path = __DIR__ . "/logs/laravel.log";

            $handler = $handler = new StreamHandler($path, 'debug');

            $handler->setFormatter(tap(new LineFormatter(null, null, true, true), function ($formatter) {
                /** @var LineFormatter $formatter */
                $formatter->includeStacktraces();
            }));

            /** @var \Monolog\Logger $monolog */
            $monolog->pushHandler($handler);
        });

        //setup db config if needed
        //$app['config']->set('database.default', 'testbench');
        //$app['config']->set('database.connections.testbench', [
        //    'driver' => 'sqlite',
        //    'database' => ':memory:',
        //    'prefix' => '',
        //]);

        $app['config']->set('app.debug', env('APP_DEBUG', true));
                //Does my pacakge had any default configurations I want to set
        //$app['config']->set('laravel-feature-flag.logging', true);
    }
}

Also:

composer require --dev "mockery/mockery:0.9.*"

Since I use this a lot to mock and it does not come with "orchestra/testbench"

Now I am ready to run tests.

Here is a sample on

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
use AlfredNutileInc\HPClient\UserFromResource;
use function GuzzleHttp\json_decode;

class UserFromResourceTest extends TestCase
{

    use UserFromResource;

    public function testResultsFromPayload()
    {
        $users = \File::get(base_path("tests/fixtures/resources.json"));
        $payload = \File::get(base_path("tests/fixtures/comments_report_limited.json"));

        $results = $this->transformResouceToResourceName(json_decode($payload, true), json_decode($users, true));

        $result = array_first($results);
        $this->assertArrayHasKey('user_name', $result);
        $this->assertEquals('Rob Sherali', $result['user_name']);
    }
}

I can easily use Facades, helpers etc that I am use to from Laravel. And I can see logs in logs/laravel.log

Also I add

    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="MAIL_DRIVER" value="array"/>
    </php>

To my phpunit.xml.dist so it can set defaults as Laravel does.