Running one specific Laravel migration (single file) - migration

I don't want to run All Outstanding Migrations on laravel 4. I have 5 migrations. Now I just want to run one migration.
instead of doing : php artisan migrate
I would like to run one specific migration like : php artisan migrate MY_MIGRATION_TO_RUN

Looks like you're doing it wrong.
Migrations were made to be executed by Laravel one by one, in the exact order they were created, so it can keep track of execution and order of execution. That way Laravel will be able to SAFELY rollback a batch of migrations, without risking breaking your database.
Giving the user the power to execute them manually, make it impossible to know (for sure) how to rollback changes in your database.
If your really need to execute something in your database, you better create a DDL script and manually execute it on your webserver.
Or just create a new migration and execute it using artisan.
EDIT:
If you need to run it first, you need to create it first.
If you just need to reorder them, rename the file to be the first. Migrations are created with a timestemp:
2013_01_20_221554_table
To create a new migration before this one you can name it
2013_01_19_221554_myFirstMigration

You can put migrations in more folders and run something like:
php artisan migrate --path=/app/database/migrations/my_migrations

Just move the already run migrations out of the app/config/database/migrations/ folder . Then run the command php artisan migrate . Worked like a charm for me .

A nice little snippet to ease any fears when running Laravel 4 migrations php artisan migrate --pretend . This will only output the SQL that would have been run if you ran the actual migration.
It sounds like your initial 4 migrations have already been run. I would guess that when you php artisan migrate it will only run the new, recent migration.
Word of advice: makes sure all of your up() and down() work how you expect them to. I like to run up(), down(), up() when I run my migrations, just to test them. It would be awful for you to get 5-6 migrations in and realize you can't roll them back without hassle, because you didn't match the down() with the up() 100% percent.
Just my two cents! Hope the --pretend helps.

The only way to re run a migrattion is a dirty one. You need to open your database and delete the line in the migrations table that represents your migration.
Then run php artisan migrate again.

You can create a separate directory for your migrations from your terminal as follows:
mkdir /database/migrations/my_migrations
And then move the specific migration you want to run to that directory and run this command:
php artisan migrate --path=/database/migrations/my_migrations
Hope this helps!

If you want to run(single file) migration in Laravel you would do the following:
php artisan migrate --path=/database/migrations/migrations_file_name
eg.
C:\xampp\htdocs\laravelv3s>php artisan migrate --path=/database/migrations/2020_02_14_102647_create_blogs_table.php

I gave this answer on another post, but you can do this: run artisan migrate to run all the migrations, then the following SQL commands to update the migrations table, making it look like the migrations were run one at a time:
SET #a = 0;
UPDATE migrations SET batch = #a:=#a+1;
That will change the batch column to 1, 2, 3, 4 .. etc. Add a WHERE batch>=... condition on there (and update the initial value of #a) if you only want to affect certain migrations.
After this, you can artisan migrate:rollback as much as is required, and it'll step through the migrations one at a time.

You can use below solution:
create your migration.
check your migration status like: php artisan migrate:status.
copy the full name of new migration and do this like: php artisan migrate:rollback --path:2018_07_13_070910_table_tests.
and then do this php artisan migrate.
finally, you migrate specific table.
Goodluck.

If you want to run your latest migration file you would do the following:
php artisan migrate
You can also revert back to before you added the migration with:
php artisan migrate: rollback

There is one easy way I know to do this can only be available for you on just local host
Modify your migration file as needed
open your phpMyAdmin or whatever you use to see your database table
find the desired table and drop it
find migrations table and open it
in this table under migration field find your desired table name and delete its row
finally run the command php artisan migrate from your command line or terminal. this will only migrate that tables which not exists in the migrations table in database.
This way is completely safe and will not make any errors or problems while it looks like un-professional way but it still works perfectly.
good luck

If it's just for testing purposes, this is how i do it:
For my case, i have several migrations, one of them contains App-Settings.
While I'm testing the App and not all of the migrations are already setup i simply move them into a new folder "future". This folde won't be touched by artisan and it will only execute the migration you want.
Dirty workaround, but it works...

I have same problem.
Copy table creation codes in first migration file something like below:
public function up()
{
Schema::create('posts', function(Blueprint $table){
$table->increments('id');
// Other columns...
$table->timestamps();
});
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
// Other columns...
$table->softDeletes()->nullable();
});
}
Also you can change(decrease) batch column number in migrations table ;)
And then run php artisan migrate.

Throw an exception in a migration, if you don't want to apply it, and it would stop the whole process of migration.
Using this approach you can split your bunch of migrations into steps.

Working in Laravel 8+
Run single specific migration:
php artisan migrate --path=/database/migrations/yourfilename.php
Run all migrations:
php artisan migrate

so simple...! just go to your migration folder. move all migration files into another folder. then return all migration one by one into migration folder and run migration for one of them(php artisan). when you insert bad migration file into master migration folder and run php artisan migrate in command prompt will be error.

I used return on line 1 so the previous dbs are retained as it is.
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
return; // This Line
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 50);
$table->string('slug', 50)->unique();
$table->integer('role_id')->default(1);
$table->string('email', 50)->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('mobile', 10)->unique();
$table->timestamp('mobile_verified_at')->nullable();
$table->text('password');
$table->integer('can_login')->default(1);
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
return;// This Line
Schema::dropIfExists('users');
}
}

This is a bad approach of which I use.. I'll delete other migration files except the specific file I want to migrate then run PHP artisan migrate after migration is completed I'll goto my trash bin and restore the deleted files

For anybody still interested in this, Laravel 5 update: Laravel has implemented the option to run one migration file at a time (in version 5.7).
You can now run this:
php artisan migrate --path=/database/migrations/my_migration.php (as answered here)
Because the Illuminate\Database\Migrations\Migrator::getMigrationFiles() now contains this code:
return Str::endsWith($path, '.php') ? [$path] : $this->files->glob($path.'/*_*.php');
(see the source code.)
But in my usecase, I actually wanted to run a set of migrations at the same time, not just one, or all.
So I went the Laravel way and registered a different implementation of the Migrator, which decides which files to use:
/**
* A migrator that can run multiple specifically chosen migrations.
*/
class MigrationsSetEnabledMigrator extends Migrator
{
/**
* #param Migrator $migrator
*/
public function __construct(Migrator $migrator)
{
parent::__construct($migrator->repository, $migrator->resolver, $migrator->files);
// Compatibility with versions >= 5.8
if (isset($migrator->events)) {
$this->events = $migrator->events;
}
}
/**
* Get all of the migration files in a given path.
*
* #param string|array $paths
* #return array
*/
public function getMigrationFiles($paths)
{
return Collection::make($paths)->flatMap(function ($path) {
return Str::endsWith($path, ']') ? $this->parseArrayOfPaths($path) :
(Str::endsWith($path, '.php') ? [$path] : $this->files->glob($path . '/*_*.php'));
})->filter()->sortBy(function ($file) {
return $this->getMigrationName($file);
})->values()->keyBy(function ($file) {
return $this->getMigrationName($file);
})->all();
}
public function parseArrayOfPaths($path)
{
$prefix = explode('[', $path)[0];
$filePaths = explode('[', $path)[1];
$filePaths = rtrim($filePaths, ']');
return Collection::make(explode(',', $filePaths))->map(function ($filePath) use ($prefix) {
return $prefix . $filePath;
})->all();
}
}
We have to register it into the container as 'migrator' (to be accessible as $app['migrator']), because that is how Migrate command accesses it when itself is being registered into the IoC. To do so, we put this code into a service provider (in my case, it is a DatabaseServiceProvider):
public function register()
{
$this->app->extend('migrator', function ($migrator, $app) {
return new MultipleSpecificMigrationsEnabledMigrator($migrator);
});
// We reset the command.migrate bind, which uses the migrator - to
// force refresh of the migrator instance.
$this->app->instance('command.migrate', null);
}
Then you can run this:
php artisan migrate --path=[database/migrations/my_migration.php,database/migrations/another_migration.php]
Notice the multiple migration files, separated by a comma.
It is tested and working in Laravel 5.4 and should be Laravel 5.8 compatible.
Why?
For anyone interested: the usecase is updating the version of database along with it's data.
Imagine, for example, that you wanted to merge the street and house number of all users into new column, let's call it street_and_house. And imagine you wanted to do that on multiple installations in a safe and tested way - you would probably create a script for that (in my case, I create data versioning commands - artisan commands).
To do such an operation, you first have to load the users into memory; then run the migrations to remove the old columns and add the new one; and then for each user assign the street_and_house=$street . " " . $house_no and save the users. (I am simplifying here, but you can surely imagine other scenarios)
And I do not want to rely on the fact that I can run all the migrations at any given time. Imagine that you wanted to update it from let's say 1.0.0 to 1.2.0 and there were multiple batches of such updates – performing any more migrations could break your data, because those migrations must be handled by their own dedicated update command. Therefore, I want to only run the selected known migrations which this update knows how to work with, then perform operations on the data, and then possibly run the next update data command. (I want to be as defensive as possible).
To achieve this, I need the aforementioned mechanism and define a fixed set of migrations to be run for such a command to work.
Note: I would have preferred to use a simple decorator utilizing the magic __call method and avoid inheritance (a similar mechanism that Laravel uses in the \Illuminate\Database\Eloquent\Builder to wrap the \Illuminate\Database\Query\Builder), but the MigrateCommand, sadly, requires an instance of Migrator in it's constructor.
Final note: I wanted to post this answer to the question How can I run specific migration in laravel , as it is Laravel 5 - specific. But I can not - since that question is marked as a duplicate of this one (although this one is tagged as Laravel 4).

You may type the following command:
php artisan migrate --help
...
--path[=PATH] The path(s) to the migrations files to be executed (multiple values allowed)
...
If it does show an option called "--path" (like the upper example) that means your Laravel version supports this parameter. If so, you're in luck can then you can type something like:
php artisan migrate --path=/database/migrations/v1.0.0/
Where "v.1.0.0" is a directory that exists under your "/database/migrations" directory that holds those migrations you want to run for a certain version.
If not, then you can check in your migrations table to see which migrations have already been run, like this:
SELECT * FROM migrations;
And then move out of your "/database/migrations" folder those which were executed. By creating another folder "/databases/executed-migrations" and moving your executed migrations there.
After this you should be able to execute:
php artisan migrate
Without any danger to override any existing table in your schema/database.

(*) example for Windows:
php artisan migrate --path=database\migrations\2021_05_18_121604_create_service_type_table.php

Related

Running manifests (classes) from a task or plan in Puppet Enterprise

TL;DR
In Puppet Enterprise, how do I run a manifest (testpp.pp) from a task or plan (not Bolt).
plan base_windows::testplan (
  TargetSpec $targets,
  Optional[String] $contents = undef,
  String $filename,
){
  $apply_prep($targets)
  $apply_results = apply($targets, '_catch_errors' => true) {
    class { 'base_windows::testpp': }
  }
  $apply_results.each | $result | {
    notice($result.report)
  }
}
apply_prep seems to succeed, but apply is failing with the following error:
{
"msg" : "Evaluation Error: Unknown function: 'report'. (file: /opt/puppetlabs/server/data/orchestration-services/code/environments/development/modules/base_windows/plans/testplan.pp, line: 16, column: 19)",
"kind" : "bolt/plan-failure",
"details" : {
"class" : "Bolt::PAL::PALError"
}
}
If I change the code to:
plan base_windows::testplan (
  TargetSpec $targets,
  Optional[String] $contents = undef,
  String $filename,
){
  apply_prep($targets)
  $apply_results = apply($targets, '_catch_errors' => true) {
# Is this how to call a class? I cannot find an example.    
class { 'base_windows::testpp': }
  }
  $apply_results.each |$result| {
$target = $result.target.name
if $result.ok {
  out::message("${target} returned a value: ${result.value}")
} else {
 out::message("${target} errored with a message: ${result.error.message}")
}
  }
}
The plan tells me it has failed, but there are no errors in the node's report. In fact, there is no entry for the time the plan was executed.
I cannot find any examples on how to call a class from a plan, so the above apply() is a guess, based on this documentation.
I have installed the puppetlabs_reboot module and successfully ran a plan using it, therefore, I conclude my system is set up correctly, it's just my code that is wrong.
Background
I may be going about this all wrong, so here is some background to the problem. Currently, I have a series of manifests that install various packages from the public Chocolatey repository depending on a node's classification. Package definitions are stored in Hiera data and each package' version is set to latest. At the end of the Package{} resource, some manifests include a reboot.
These manifests are used to provision new nodes and keep existing nodes up-to-date with the latest package version.
The Puppet agent is set to run once per hour and if the source package is updated in the Chocolatey repo, on the next Puppet run, the manifest will update the package, rebooting the node, if required.
Goal
New nodes are provisioned with the latest package version.
Prevent package updates at undetermined times on existing nodes.
Continue to allow Puppet agent runs every hour.
Make use of existing manifests.
Ideas
Split out the package{} code from the profile manifest and place them in tasks / plans, allowing packages to be updated out-of-hours.
Specify the actual package version in Hiera. Although this is more declarative and idempotent, it means keeping an eye on over 100 package version. I guess it would be fairly simple to interrogate the Chocolatey repos with code to pull the latest version number, but even so I am no better off.
Create a task with a script that runs choco upgrade all, however, the next Puppet run would revert package versions according to the version defined in Hiera, meaning Hiera still needs to be kept up-to-date.
Problems
As per the main crux of this question, how do I run manifests (classes) from plans? If I understand correctly, tasks are for ad-hoc scripts, whereas plans can run tasks and manifests. As a lot of time has been invested in writing manifests, I would prefer not to rewrite all my manifests as scripts.
I am confused by the Puppet documentation as it seems to switch between PE and Bolt syntax. I am using Puppet Enterprise where Puppet says they don't recommend using Bolt but their examples seem to site Bolt commands.
No errors in the node' report. apply_prep() reports executed successfully, albeit taking far longer to execute than puppetlabs_reboot module, but apply() results in a failure, but nothing is logged in the node's reports.
Using puppetlabs_reboot module as a reference, it appears their plan uses a bunch of tasks. It appears that they don't use apply() to run their reboot{} class. Is this not duplicating the work?
If anyone has any suggestions or ideas, I'd be grateful if you could share.
I've got it to work. The class I was trying to run, required parameters that I hadn't provided!
plan base_windows::testplan (
TargetSpec $targets,
Optional[String] $contents = undef,
String $filename,
){
apply_prep($targets)
$apply_results = apply($targets, '_catch_errors' => true) {
class { 'base_windows::testpp':
filename => $filename,
contents => $contents,
}
}
}
# Output the whole result_set in the PE console
return $apply_results
I found this out using the logs.
Turn on debug level logging in /etc/puppetlabs/puppetserver/logback.xml (root level="debug")
Tail the following logs:
tail -f /var/log/puppetlabs/bolt-server/bolt-server.log
tail -f /var/log/puppetlabs/puppetserver/puppetserver.log | grep -B 5 -A 5 'testplan'
tail -f /var/log/puppetlabs/orchestration-services/orchestration-services.log

Laravel Reset Database after Test

I have just started using Laravel Dusk to test my project and need some guidance. After I run all the tests available, I want to be able to reset my database back to before I run the tests. (If there were any entries in my database before I run the tests, I would still like to see them after I run the tests. However, any entires created during the test, I would not like to see them after the tests finish running.) Any pointers on how I would achieve this? Thank you!
Update:
<?php
namespace Tests\Browser;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class UserRegisterTest extends DuskTestCase
{
use DatabaseTransactions;
/**
* A test for user registration.
* #group register
* #return void
*/
public function testRegisterUser()
{
//Register with all info filled out correctly
$this->browse(function ($browser){
$browser->visit('/register')
->type('firstName', 'JenLogin')
->type('lastName', 'Zhou')
->type('email', 'testLogin#gmail.com')
->type('bio', 'Hello, this user is for testing login purposes!')
->type('location_zip', '11111')
->type('password', '123456')
->type('password_confirmation', '123456')
->click('.btn-primary')
->assertPathIs('/home')
->click('.dropdown-toggle')
->click('.dropdown-menu li:last-child');
});
$this->assertDatabaseHas('users', ['firstName' => 'JenLogin', 'lastName' => 'Zhou', 'email' => 'testLogin#gmail.com']);
}
/**
* Register with duplicate user
* #group register
* #return void
*/
public function testRegisterDuplicateUser(){
$this->browse(function ($browser){
$browser->visit('/register')
->type('firstName', 'JenLoginDup')
->type('lastName', 'Zhou')
->type('email', 'testLogin#gmail.com')
->type('bio', 'Hello, this user is for testing login purposes!')
->type('location_zip', '11111')
->type('password', '123456')
->type('password_confirmation', '123456')
->click('.btn-primary')
->assertPathIs('/register')
->assertSee('The email has already been taken.');
});
$this->assertDatabaseMissing('users', ['firstName' => 'JenLoginDup', 'lastName' => 'Zhou', 'email' => 'testLogin#gmail.com']);
}
/**
* Register with incorrect password confirmation
* #group register
* #return void
*/
public function testRegisterUserNoPassConfirm(){
$this->browse(function ($browser){
$browser->visit('/register')
->type('firstName', 'JenLoginPass')
->type('lastName', 'Zhou')
->type('email', 'testLoginPass#gmail.com')
->type('bio', 'Hello, this user is for testing login purposes!')
->type('location_zip', '11111')
->type('password', '123456')
->type('password_confirmation', '888888')
->click('.btn-primary')
->assertPathIs('/register')
->assertSee('The password confirmation does not match.');
});
$this->assertDatabaseMissing('users', ['firstName' => 'JenLoginPass', 'lastName' => 'Zhou', 'email' => 'testLoginPass#gmail.com']);
}
}
You are looking for the DatabaseTransactions trait. Use it in your test class like this and it will automatically rollback all database transactions made during your tests.
use Illuminate\Foundation\Testing\DatabaseTransactions;
class ExampleTest extends TestCase
{
use DatabaseTransactions;
// test methods here
}
This will keep track of all transactions made during your test and undo them upon completion.
note: this trait only works on default database connections
First of all, when you are running tests you should use completely different database than your live (or dev) database. For this you should create .env.dusk and set in there:
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=testing_database
DB_USERNAME=root
DB_PASSWORD=pass
to database used for tests only.
Second thing is that for Laravel Dusk you cannot use just DatabaseTransactions. You should in fact use DatabaseMigrations for Dusk tests otherwise you will get unexpected results.
There is no sane workflow for running tests on live/dev db with data and reverting changes back, done by tests.
Therefore your approach fails here, instead you should:
Create separate test schema/db for tests
Switch to test db, before running tests - this can be somehow automated depending on your configuration in phpunit and .env.dusk, but it depends on your local setup.
Then in your tests you will create all from scratch on clean db (run migrations, seeds, factories)
Run tests against this test db
For development switch back to your base db with current data, which will not be affected by tests.
Next time you will run your tests all starts again from point zero - clean database, this will be done by in tests:
use CreatesApplication;
use DatabaseMigrations;
parent::setUp();etc.
Read more about these methods...
Side Notes:
With this approach, it will be easy, to test your app in CI environments also.
Never write your tests which depend on data on your dev/live db. For tests all required data should be provided by seeds or ewentually factories!
You can use the RefreshDatabase trait in your test classes.After each test the database will be like before test.
In Fact it will drop all tables and migrate again.
If you would not loose your data you can use one separate schema for test.
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
}
For multiple databases, this helped me
class MyTest extends TestCase {
// Reset the DB between tests
use DatabaseTransactions;
// Setting this allows both DB connections to be reset between tests
protected $connectionsToTransact = ['mysql', 'myOtherConnection'];
}
I think this is a great question. I found an Artisan tool that may be what you are looking for. You can use it to take a snapshot of the database before you run the test and then use it again to load that snapshot restoring your database to the previous state. I gave it a run(using MYSQL) and it worked great. Hope this is what you are looking for. Here is a link...
https://github.com/spatie/laravel-db-snapshots
phpunit.xml file is your solution there, you can set a .env variables in this file like so
<env name="DB_CONNECTION" value="testing_mysql"/>
<env name="DB_DATABASE_TEST" value="test"/>
now you can run your tests on a separate database.
Plus you can run a .php file every time before tests in automation, you just need to tell it to unittests
<phpunit
...
bootstrap="tests/autoload.php"
>
You can put any cleaners or seeders there or something like
echo 'Migration -begin-' . "\n";
echo shell_exec('php artisan migrate:fresh --seed');
echo 'Migration -end-' . "\n";

Laravel update database record running script

I want to update any records in my database running SQL script using artisan. For example, I need to execute such command:
UPDATE translations SET field = 'meta_desc' WHERE field = 'page_desc'
What the Laravel's sctructure will be the best solution? Seed, migrations, factories?
Thanks to everybody for replies. Ecpesially thanks to #RossWilson for his idea of using migrations for changing DB's data.
But I think, it's not a good solution, because the Laravel's concept involves using migrations for DB structure's changing.
After reading Laravel's manuals I've found that there is a special code structure for working with db's data. It's a Seed. So, I solved my issue using the next seed for my example query above:
Created the new seed using artisan command:
php artisan make:seed UpdateTranslationsSeeder
Write a code inside the run() method:
DB::table('translations')->where('field', 'page_desc')->update(['field' => 'meta_desc']);
Run my seeder in artisan:
php artisan db:seed --class=UpdateTranslationsSeeder
Note: if after running the last command in console I've got an error about class UpdateTranslationsSeeder is undefined run the next command in console to tell Laravel about new classes:
composer dump-autoload -o
I have adapted Paul Basenko approach to updating existing data for educational purposes. It was very useful! Here is my example:
Generate a seeder:
php artisan make:seed UpdateCustomerSeeder
Add code inside run method:
$customers = Customer::all();
$customers->each(function ($customer_update, $key) {
$faker = Factory::create('it_IT');
$customer_update->name = $faker->company;
$customer_update->website = $faker->domainName;
$customer_update->tax_number = $faker->vatId();
$customer_update->phone = $faker->phoneNumber;
$customer_update->email = $faker->safeEmail;
$customer_update->street = $faker->streetAddress;
$customer_update->city = $faker->city;
$customer_update->zip_code = $faker->postcode;
$customer_update->notes = $faker->sentence();
$customer_update->save();
});
Run seeder:
php artisan db:seed --class=UpdateCustomerSeeder

How to generate views from migrations in Laravel?

I am using Laravel 5.4 and the package migrations-generator that generates migrations.
So I have the migrations and now I need to generate the views automatically using Artisan. I tried it on Symfony and it was so easy but I can't do it with Laravel.
Here is an example of a migration file called 2017_07_01_202030_create_personas_table.php for persons.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreatePersonasTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('personas', function(Blueprint $table)
{
$table->integer('id', true);
$table->string('nombre', 100);
$table->dateTime('fecha_de_nacimiento');
$table->softDeletes();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('personas');
}
}
I tried more than eight packages to resolve my problem: generate model, views and controller from a table (on Laravel 5.4) but they don't work. Else I will use the Yii Framework that works great.
php artisan make:controller MyController -r --model=MyModel
It will generate Controller with REST function inside them. & also create model if its not created.
You can also use below command to generate migration while creating Model
php artisan make:Model MyModel --migration
& For manage views you can use this. I haven't used it yet but come to see this package suggest by many time.
https://github.com/svenluijten/artisan-view
Hope this help.
If you want an easy way to generate migration and views in a single artisan command, just install & use this popular package from Jeffrey Way https://github.com/laracasts/Laravel-5-Generators-Extended. Just follow the steps from that page.

Code coverage in SimpleTest

Is there any way to generate code coverage report when using SimpleTest similar to PHPUnit.
I have read the documentation of SimpleTest on their website but can not find a clear way on how to do it!
I came across this website that says
we can add require_once (dirname(__FILE__).'/coverage.php')
to the intended file and it should generate the report, but it did not work!
If there is a helpful website on how to generate code coverage, please share it here.
Thanks alot.
I could not get it to work in the officially supported way either, but here is something I got working that I was able to hack together by examining their code. This works for v1.1.7 of SimpleTest, not their master code. At the time of this writing v1.1.7 is the latest release, and works with new versions of PHP 7, even though it is an old release.
First off you have to make sure you have Xdebug installed, configured, and working. On my system there is both a CLI and Apache version of the php.ini file that have to be configured properly depending on if I am trying to use PHP through Apache or just directly from the terminal. There are alternatives to Xdebug, but most people us Xdebug.
Then, you have to make the PHP_CodeCoverage library accessible from your code. I recommend adding it to your project as a composer package.
Now you just have to manually use that library to capture code coverage and generate a report. How exactly you do that will depend on how you run your tests. Personally, I run my tests on the terminal, and I have a bootstrap file that php runs before it starts the script. At the end of the bootstrap file, I include the SimpleTest autorun file so it will automatically run the tests in any test classes that get included like so:
require_once __DIR__.'/vendor/simpletest/simpletest/autorun.php';
Somewhere inside your bootstrap file you will need to create a filter, whitelist the directories and files you want to get reported, create a coverage object and pass in the filter to the constructor, start coverage, and create and register a shutdown function that will change the way SimpleTest executes the tests to make sure it also stops the coverage and generates the coverage report. Your bootstrap file might look something like this:
<?php
require __DIR__.'/vendor/autoload.php';
$filter = new \SebastianBergmann\CodeCoverage\Filter();
$filter->addDirectoryToWhitelist(__DIR__."/src/");
$coverage = new \SebastianBergmann\CodeCoverage\CodeCoverage(null, $filter);
$coverage->start('<name of test>');
function shutdownWithCoverage($coverage)
{
$autorun = function_exists('\run_local_tests'); // provided by simpletest
if ($autorun) {
$result = \run_local_tests(); // this actually runs the tests
}
$coverage->stop();
$writer = new \SebastianBergmann\CodeCoverage\Report\Html\Facade;
$writer->process($coverage, __DIR__.'/tmp/code-coverage-report');
if ($autorun) {
// prevent tests from running twice:
exit($result ? 0 : 1);
}
}
register_shutdown_function('\shutdownWithCoverage', $coverage);
require_once __DIR__.'/vendor/simpletest/simpletest/autorun.php';
It took me some time to figure out, as - to put it mildly - the documentation for this feature is not really complete.
Once you have your test suite up and running, just include these lines before the lines that are actually running it:
require_once ('simpletest/extensions/coverage/coverage.php');
require_once ('simpletest/extensions/coverage/coverage_reporter.php');
$coverage = new CodeCoverage();
$coverage->log = 'coverage/log.sqlite'; // This folder should exist
$coverage->includes = ['.*\.php$']; // Modify these as you wish
$coverage->excludes = ['simpletest.*']; // Or it is even better to use a setting file
$coverage->maxDirectoryDepth = '1';
$coverage->resetLog();
$coverage->startCoverage();
Then run your tests, for instance:
$test = new ProjectTests(); //It is an extension of the class TestSuite
$test->run(new HtmlReporter());
Finally generate your reports
$coverage->stopCoverage();
$coverage->writeUntouched();
$handler = new CoverageDataHandler($coverage->log);
$report = new CoverageReporter();
$report->reportDir = 'coverage/report'; // This folder should exist
$report->title = 'Code Coverage Report';
$report->coverage = $handler->read();
$report->untouched = $handler->readUntouchedFiles();
$report->summaryFile = $report->reportDir . '/index.html';
And that's it. Based on your setup, you might need to make some small adjustment to make it work. For instance, if you are using the autorun.php from simpletest, that might be a bit more tricky.