goatshark's avatar

I Forget Test Methods

Greetings,

I wrote an artisan command to compensate for my constantly losing sight of what test methods I've already written for a project. While I am certain this is wheel already exists, I couldn't find it in all the other wheels. ....I'm not even sure which wheel yard to look in actually.

Maybe someone can tell me which wheel I reinvented.

Btw, this should work, on it's own, dropped into app/Console/Commands.

<?php

namespace App\Console\Commands;

use App\TestFinder;
use Illuminate\Console\Command;

class FindTests extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'goat:list-tests';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'List methods starting with \'test_\' in test files ending in \'Test.php\'';

    /**
     * Path to test files
     * @var string
     */
    public $tests_path;

    /**
     * The suffix at the end of test file names
     * @var string
     */
    public $testfile_suffix = 'Test.php';

    /**
     * The prefix used on methods in tests
     * @var string
     */
    public $testmethod_prefix = 'test_';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();

        $this->tests_path = base_path('tests/Feature');
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $table_headers = ['Class', 'Tests'];

        $results = $this->getAll()->map(function($test_class, $key) {
            return [
                'class' => $test_class['class_name'],
                'tests' => implode("\n", $this->getTestMethods($test_class['class_name'])) . "\n"
            ];
        });

        $this->table($table_headers, $results);
    }

    /**
     * Create the whole dataset to return
     * @return collection
     */
    protected function getAll()
    {
        $all_classes_with_their_methods = collect();

        $this->getTestClassesWithFullPaths()->each(function($fq_class_name, $key) use ($all_classes_with_their_methods) {
            $all_classes_with_their_methods->push(collect([
                'class_name' => $fq_class_name,
                'methods' => $this->getTestMethods($fq_class_name)
            ]));
        });

        return $all_classes_with_their_methods;
    }

    /**
     * Get all test classes with paths
     * @return collection
     */
    protected function getTestClassesWithFullPaths()
    {
        $test_classes = $this->getTestFiles()->map(function($filename, $key) {
            return 'Tests\Feature\' . str_before($filename, '.php');
        });

        return $test_classes;
    }

    /**
     * Filter out any filenames that don't end with $this->testfile_suffix
     * @return collection
     */
    protected function getTestFiles()
    {
        $test_files = $this->scanDir()->filter(function($filename, $key) {
            return ends_with($filename, $this->testfile_suffix);
        });

        return $test_files;
    }

    /**
     * Filter all the methods to grab just the ones that start with test_
     *
     * @param  string $class_name Class name with path
     * @return array
     */
    protected function getTestMethods($class_name)
    {
        $test_methods = collect(get_class_methods(new $class_name))->filter(function($method, $key) {
            return starts_with($method, $this->testmethod_prefix);
        });

        return $test_methods->toArray() ?: ['no tests'];
    }

    /**
     * This is a raw scandir, so you'll get "." and ".." along with
     * every other file in $this->tests_path;
     *
     * @return collection List of files and directories
     */
    protected function scanDir()
    {
        return collect(scandir($this->tests_path));
    }
}
0 likes
2 replies
tykus's avatar
tykus
Best Answer
Level 104

Wouldn't the --testdox option on PHPUnit provide you with the same information on CLI or other formats too!?

goatshark's avatar

@tykus As a matter of fact, --testdox does exactly what I wanted. Good thing I like throwing away code, otherwise I might be miffed that I spent any time on that command. It was a nice exercise though. I haven't written many commands.

Thank you, @tykus, that's exactly what I was looking for.

Please or to participate in this conversation.