logo

Tutorials: Unit Testing

For more info how unit tests work behind the scenes in Lucinda Framework, please go to specialized Documentation page! Unit tests bundled with Framework Skeleton API require:

  1. an already setup SQL server connection for development environment, for example MySQL
  2. an already setup NoSQL server connection for development environment, for example Redis

Setting Development Environment

Unit tests execution may be subject of differences depending on development environment (eg: using db connection settings). Unit test execution requires environment variable ENVIRONMENT to be already set:

If above is not set, framework automatically assumes {VALUE} will be local and employ mocks in order to make unit tests as development environment unspecific as possible. It is STRONGLY RECOMMENDED for developers to follow this pattern as well!

Creating Mock Database

Framework Skeleton API comes with a few tests that require an actual database connection. For that reason, assuming you are using MySQL, you MUST run:

CREATE DATABASE test; CREATE USER test@localhost IDENTIFIED BY 'me'; GRANT ALL ON test.* TO test@localhost; USE test; CREATE TABLE user_logins ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, ip VARCHAR(45) NOT NULL, username VARCHAR(255) NOT NULL, attempts BIGINT UNSIGNED NOT NULL default 0, penalty_expiration DATETIME DEFAULT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY(id), UNIQUE(ip, username) ) Engine=InnoDB; CREATE TABLE migrations ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, class_name VARCHAR(255) NOT NULL, is_successful BOOLEAN NOT NULL DEFAULT TRUE, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(id), UNIQUE(class_name) ) Engine=INNODB; CREATE TABLE sessions ( id VARCHAR(50) NOT NULL, value BLOB NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, expires INT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY(id), KEY(expires) ) Engine=INNODB;

Developing Unit-Testable Classes

All classes found in src folder are unit testable and autoloaded. Let's say we need to create a class:

namespace Lucinda\Project\MyModels; class Greeting { public function me1(): string { return "Hello, world!"; } public function me2(string $name): string { if ($name == "lucian") { return "Bye, world: ".$name; } else { return "Hello, world: ".$name; } } }

Writing Unit Tests

Now, in order to keep 100% coverage for our project, we would need to create a unit test for above. Open console, go to project root and run:

php test.php

This will create a tests/MyModels/GreetingTest file with following body:

namespace Test\Lucinda\Project\MyModels; class GreetingTest { public function me1() { } public function me2() { } }

Now you must fill methods above with code running unit test(s) on original class, returning a or a list of latter:

namespace Test\Lucinda\Project\MyModels; use Lucinda\UnitTest\Result; use Lucinda\Project\MyModels\Greeting; class GreetingTest { public function me1() { $greeting = new Greeting(); return new Result($greeting->me1()=="Hello, world!"); } public function me2() { $tests = []; $greeting = new Greeting(); $tests[] = new Result($greeting->me2("lucian")=="Bye, world: lucian"); $tests[] = new Result($greeting->me2("mihai")=="Hello, world: mihai"); return $tests; } }

Please remember that for same class tests will be ran in the order public functions are set in test class: which means in this case me1 will be ran before me2! To change order of execution, simply move methods up/down in code.

Executing Unit Tests

To execute unit tests, Open console, go to project root and run again:

php test.php

This will output results using a console table. System is flexible enough to allow any other result format: let's say we want results in a JSON form instead! In that case, we only need to change test.php:

require __DIR__ . '/vendor/autoload.php'; class JsonController extends Lucinda\UnitTest\Controller { protected function handle(array $results): void { echo json_encode($results); } } try { $environment = (getenv("ENVIRONMENT")?getenv("ENVIRONMENT"):"local"); new JsonController("unit-tests.xml", $environment); } catch (Exception $e) { echo $e->getMessage(); }
×