nateritter's avatar

[Lumen] TestDummy DbTestCase use throws errors

I was trying out the TestDummy via https://laracasts.com/lessons/whats-new-in-testdummy but using Lumen and have been unable to make it work.

If I put the parent::setUp() line inside the public function setUp() method, and get the following error:

PHP Fatal error:  Class 'Artisan' not found in .../vendor/laracasts/testdummy/src/DbTestCase.php on line 22

So, if I remove that, and leave the extends DbTestCase on the class, I get the following error:

PHP Fatal error:  Call to a member function prepareResponse() on a non-object in .../vendor/laravel/lumen-framework/src/Testing/ApplicationTrait.php on line 58

*Note: Yes, I have se Laracasts\TestDummy\DbTestCase; above the class.

Here's my full code, as per the TestDummy Laracast video:

<?php

use Laracasts\TestDummy\Factory;
use Laracasts\TestDummy\DbTestCase;
use App\Repositories\CorpusRepository;

class PersonTest extends DbTestCase
{
    public function setUp()
    {
        parent::setup();
        $this->repository = new CorpusRepository;
    }

    public function testBasicExample()
    {
        $response = $this->call('GET', '/');
        $this->assertResponseOk();
    }

    public function testCreatePerson()
    {
        $person = Factory::create('App\Person');
        $attributes = Factory::times(2)->create('App\Attribute', ['person_id' => $person->id]);

        Factory::times(3)->create('App\Attribute');

        $attributes = $this->repository->getAttributesByUserId($person->id);

        $this->assertCount(2, $attributes);
    }
}

So, without pulling the entire Laravel core framework in, how can I get something similar to the DbTestCase's Factory::create to work and then roll back after the test is over? Or is there another way to use just the Factory to test the creation of a Person (or User as it may be)?

0 likes
1 reply
nateritter's avatar
nateritter
OP
Best Answer
Level 3

I went a completely different route and found success...

My TestCase.php is as follows:

<?php

use Illuminate\Support\Facades\Artisan as Artisan;

class TestCase extends Laravel\Lumen\Testing\TestCase
{

    public function createApplication()
    {
        return require __DIR__ . '/../bootstrap/app.php';
    }

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

        // Replace the testing.sqlite with stub.sqlite
        // stub.sqlite is kept updated by way of `gulp watch`
        // or `gulp stubdb`
        exec('rm '. __DIR__ . '/../storage/testing.sqlite');
        exec(
            'cp '. __DIR__ . '/../storage/stub.sqlite '
            . __DIR__ . '/../storage/testing.sqlite'
        );
    }

    public function tearDown()
    {
        // Leaves the databse as-is in case we want to see
        // what happened during the last run
        parent::tearDown();
    }
}

I then created a gulpfile.js with the following:

// Thanks to https://gist.github.com/duellsy/9125911
var gulp = require('gulp'),
    watch = require('gulp-watch'),
    exec = require('child_process').exec,
    phpunit = require('gulp-phpunit'),
    notify = require('gulp-notify'),
    gutil = require('gulp-util'),
    sys = require('sys');

gulp.task('phpunit', function(){
    exec('./vendor/phpunit/phpunit/phpunit tests', function(error, stdout, stderr) {
        console.log(stdout);
        console.log(stderr);
        if (error !== null) {
            notify('Unit test failed: ' + error);
            gutil.beep();
        }
    });
});

// Re-create the stub db when a migration or seed file changes
gulp.task('stubdb', function() {

    // Backup the current .env file
    exec('rm -f .env.backup');
    exec('cp .env .env.backup');

    // Replace .env with .env.stub (temporarily)
    exec('rm -f .env');
    exec('cp .env.stub .env');

    // Execute migrate command
    exec('php artisan migrate:refresh --seed', function(error, stdout) {
        sys.puts(stdout);
        if (error !== null) {
            sys.puts(error);
        }
        gulp.run('phpunit');
        // Replace .env with .env.backup
        exec('rm -f .env');
        exec('cp .env.backup .env');
    });

});

gulp.task('watch', function() {
    gulp.watch('database/**/*.php', ['stubdb']);
    gulp.watch('app/**/*.php', ['phpunit']);
    gulp.watch('app/*.php', ['phpunit']);
    // gulp.watch('tests/**/*.php', ['phpunit']);
    // gulp.watch('tests/*.php', ['phpunit']);
});

gulp.task('default', ['watch']);

And my .env.stub file looks like this:

APP_ENV=local
APP_DEBUG=true
APP_KEY=somethingcrazy

APP_LOCALE=en
APP_FALLBACK_LOCALE=en

DB_CONNECTION=sqlite
DB_DATABASE=storage/stub.sqlite

So, now you'll see that now I just run gulp and keep it going, so that it watches my migrations and seeds. If it sees anything changing, it recreates the different .env files, runs the migrate command, and then puts the .env files back (leaving some backups just in case something goes wrong).

Then, in the phpunit.xml file, I changed the environment to use "testing" like this:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="bootstrap/app.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         syntaxCheck="false">
    <testsuites>
        <testsuite name="Application Test Suite">
            <directory>./tests/unit/</directory>
        </testsuite>
    </testsuites>
    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="DB_DATABASE" value="storage/testing.sqlite"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
    </php>
</phpunit>

That way, it uses the testing.sqlite file each time, and if I ever change migrations or seeds, that file is automatically created for me based on the stub when the TestCase.php:setup() method is run.

Voila. All works like a charm and runs super duper speedy-like.

1 like

Please or to participate in this conversation.