I am writing a simple set of PHP functions, I use only pure PHP7, no framework, nothing. These functions will later on be used in a plugin in a CMS, but that is besides the point. I want to write unit tests for my functions using Codeception (to get familiar with it, I know that Codeception essentially only runs PHPUnit here), but I don't really know how to point Codeception to my code in a reasonable way.
My structure is as follows: I have path/to/functions.php
which contains the functions I want to test, something along the lines of:
<?php
namespace App;
if (!defined('CONST')) {
die('What are you doing? Get out of here!');
}
function change_string($string){
return $string . '123';
}
I have used Composer to install Codeception to the root of my project and I used Codeception bootstrap to get started and then I also used Codeception to generate the unit test file, to which I added my unit test. Now most tutorials/explanations/articles on the subject just write tests and Codeception magically knowns where to find the code to test. This makes zero sense to me, and does not work in my case. So what I did is the following:
<?php
class NamesPathsTest extends \Codeception\Test\Unit
{
/**
* @var \UnitTester
*/
protected $tester;
protected function _before()
{
defined('CONST') or define('CONST', 'XXX');
require_once('path/to/functions.php');
}
protected function _after()
{
}
// tests
public function testChangeString() {
$this->assertEquals('a123',App\change_string('a'));
}
}
This works, but I think that there must be a better way to explain to Codeception where is the code to run than using the require_once('path/to/functions.php')
. How to do this? What is the smart way of pointing Codeception to my code? Can it also handle defining the constant, so that I can actually test the functions?
How does your application code knows where the functions and classes are?
The magic ingredient is called autoloading.
Since you are using Composer already, the easiest way is to configure Composer to load your classes and functions.
Autoloading only works with classes, for them you can map namespace prefix to directory,
{
"autoload": {
"psr-4": {
"Monolog\\": "src/",
"Vendor\\Namespace\\": ""
}
}
}
Files containing functions must be included, but Composer helps with that too:
{
"autoload": {
"files": ["path/to/functions.php"]
}
}
Combined result:
{
"autoload": {
"files": ["path/to/functions.php"]
"psr-4": {
"Monolog\\": "src/",
"Vendor\\Namespace\\": ""
}
}
}
Since Codeception is installed using Composer, no additional work is required to get autoloading work in tests.
To benefit from autoloading in your application code, you must require 'vendor/autoload.php';
near the entry point.
Regarding your constant question, nobody uses this way to prevent direct execution of files, it is much simpler and more secure to move the code away from public directory and leave only small index.php file that can be accessed directly in public directory.