PHP code example of alexskrypnyk / phpunit-helpers

1. Go to this page and download the library: Download alexskrypnyk/phpunit-helpers library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

alexskrypnyk / phpunit-helpers example snippets


use AlexSkrypnyk\PhpunitHelpers\UnitTestCase;

class MyTest extends UnitTestCase {

  public function testExample(): void {
    // Test implementation that benefits from the tring {
    // Excluded from info() because the name contains "test".
    return 'This will not appear in info()';
  }

}

use AlexSkrypnyk\PhpunitHelpers\Traits\AssertArrayTrait;
use PHPUnit\Framework\TestCase;

class MyAssertArrayTest extends TestCase {

  use AssertArrayTrait;

  public function testCustomAssertions(): void {
    $array = ['This is a test', 'Another value'];

    // Assert that a string is present in one of the array values.
    $this->assertArrayContainsString('test', $array);

    // Assert with a custom failure message.
    $this->assertArrayContainsString('test', $array, 'Not found');

    // Assert that a string is absent from all array values.
    $this->assertArrayNotContainsString('missing', $array);

    // Assert that an array contains all elements of a sub-array.
    // Nested arrays are searched recursively.
    $this->assertArrayContainsArray(
      ['a', 'b', ['c', 'd']],
      ['a', ['c', 'd']]
    );

    // Assert that an array contains none of the sub-array elements.
    $this->assertArrayNotContainsArray(['a', 'b'], ['z']);
  }

}

use AlexSkrypnyk\PhpunitHelpers\Traits\ApplicationTrait;
use PHPUnit\Framework\TestCase;

class MyApplicationTest extends TestCase {

  use ApplicationTrait;

  protected function setUp(): void {
    // Working directory, NULL for the current PHP process directory.
    $this->applicationCwd = NULL;
    // Whether to show the output during execution.
    $this->applicationShowOutput = FALSE;
  }

  protected function tearDown(): void {
    $this->applicationTearDown();
  }

  public function testConsoleApplication(): void {
    // Initialize the application from a loader file that returns an
    // Application instance.
    $this->applicationInitFromLoader('/path/to/application_loader.php');

    // Or initialize it from a command class or object. The second
    // argument makes it the single default command.
    $this->applicationInitFromCommand(MyCommand::class, TRUE);

    // Both initializers return the ApplicationTester. The application
    // and the tester are also available on demand.
    $application = $this->applicationGet();
    $tester = $this->applicationGetTester();

    // Run the application with input arguments and options.
    $output = $this->applicationRun(
      // Input arguments and options.
      ['argument1', '--option1=value1'],
      // Application tester options.
      ['capture_stderr_separately' => TRUE],
      // Whether a failure is expected. Defaults to FALSE.
      FALSE
    );

    // Assert on the exit code.
    $this->assertApplicationSuccessful();
    $this->assertApplicationFailed();

    // Assert that the output contains string(s).
    $this->assertApplicationOutputContains('Expected output');
    $this->assertApplicationOutputContains(['String1', 'String2']);
    $this->assertApplicationOutputContains('Expected', 'Not found');

    // Assert that the output does not contain string(s).
    $this->assertApplicationOutputNotContains('Unexpected output');

    // The same assertions are available for the error output.
    $this->assertApplicationErrorOutputContains('Expected error');
    $this->assertApplicationErrorOutputNotContains('Unexpected error');

    // And for the standard and error output combined.
    $this->assertApplicationAnyOutputContains('In either output');
    $this->assertApplicationAnyOutputNotContains('In neither output');

    // Assert several conditions in one call using prefixes. See the
    // StringTrait section for the full prefix reference.
    // Shortcut mode: no prefixes, all must be present as substrings.
    $this->assertApplicationOutputContainsOrNot(['Expected', 'Output']);

    // Mixed mode: if any string has a prefix, all of them must.
    $this->assertApplicationOutputContainsOrNot([
      // Present as a substring.
      '* Expected',
      // Absent as a substring.
      '! Unexpected',
    ]);
    $this->assertApplicationErrorOutputContainsOrNot(['* Error']);
    $this->assertApplicationAnyOutputContainsOrNot(['* Either', '! No']);

    // '+' and '-' compare against the whole trimmed output, so they
    // only make sense for a single-line output.
    $this->assertApplicationOutputContainsOrNot([
      // The whole output must equal this.
      '+ Hello, World!',
    ]);

    // Get debug info about the application (output, error output).
    echo $this->applicationInfo();
  }

}

use AlexSkrypnyk\PhpunitHelpers\Traits\EnvTrait;
use PHPUnit\Framework\TestCase;

class MyEnvTest extends TestCase {

  use EnvTrait;

  public function testEnvironmentVariables(): void {
    // Set an environment variable.
    self::envSet('MY_VAR', 'value');

    // Set multiple environment variables.
    self::envSetMultiple(['VAR1' => 'value1', 'VAR2' => 'value2']);

    // Get an environment variable. Returns FALSE when it is not set.
    $value = self::envGet('MY_VAR');

    // Check whether an environment variable is set.
    $is_set = self::envIsSet('MY_VAR');
    $is_unset = self::envIsUnset('MY_VAR');

    // Unset an environment variable.
    self::envUnset('MY_VAR');

    // Unset multiple environment variables.
    self::envUnsetMultiple(['VAR1', 'VAR2']);

    // Unset every environment variable with a given prefix.
    self::envUnsetPrefix('MY_');

    // Set environment variables from an input array. Matching entries
    // are removed from the input array unless the third argument is
    // FALSE.
    $input = ['MY_VAR' => 'value', 'other' => 'kept'];
    self::envFromInput($input, 'MY_');

    // Unset every variable that was set through this trait.
    self::envReset();
  }

}

use AlexSkrypnyk\PhpunitHelpers\Traits\LocationsTrait;
use PHPUnit\Framework\TestCase;

class MyLocationsTest extends TestCase {

  use LocationsTrait;

  protected function setUp(): void {
    // Create the test directories.
    $this->locationsInit();

    // Root directory of the project.
    echo self::$root;
    // Fixtures directory, or NULL when it does not exist.
    echo self::$fixtures;
    // Workspace directory holding the assets of a single test run.
    echo self::$workspace;
    // Source directory for operations.
    echo self::$repo;
    // System Under Test directory where the test runs.
    echo self::$sut;
    // Temporary files directory.
    echo self::$tmp;

    // The same paths are available through accessors.
    echo self::locationsRoot();
    echo self::locationsFixtures();
    echo self::locationsWorkspace();
    echo self::locationsRepo();
    echo self::locationsSut();
    echo self::locationsTmp();

    // Print all locations at once.
    echo self::locationsInfo();
  }

  protected function tearDown(): void {
    // Remove the workspace directory and everything below it.
    $this->locationsTearDown();
  }

  /**
   * Override to point at a different fixtures directory.
   *
   * Defaults to 'tests/Fixtures', relative to the repository root.
   */
  public static function locationsFixturesDir(): string {
    return 'tests/Fixtures';
  }

  public function testFileOperations(): void {
    // Get a named fixtures directory, creating it if needed.
    $fixtures_dir = $this->locationsFixtureDir('my-fixture');

    // Without a name, the directory is derived from the test name, and
    // a named data set adds a further subdirectory. The data set named
    // 'baseline' maps to the '_baseline' directory.
    $fixtures_dir = $this->locationsFixtureDir();

    // Copy files into the SUT directory. A random numeric suffix is
    // appended to each name, so the created paths are returned rather
    // than derived.
    $files = self::locationsCopyFilesToSut(['file1.txt', 'file2.txt']);
    $this->assertFileExists($files[0]);

    // Pass FALSE as the third argument to keep the original names.
    $files = self::locationsCopyFilesToSut(['file1.txt'], NULL, FALSE);
    $this->assertFileExists(self::$sut . '/file1.txt');

    // Copy between arbitrary directories. '.git', 'node_modules' and
    // 'vendor' are always excluded.
    $created = self::locationsCopy(self::$repo, self::$sut);

    // Create a directory if needed and return its real path.
    $path = self::locationsMkdir(self::$tmp . '/nested');

    // Resolve a real path, throwing when it does not exist.
    $real = self::locationsRealpath($path);
  }

}

use AlexSkrypnyk\PhpunitHelpers\Traits\ProcessTrait;
use PHPUnit\Framework\TestCase;

class MyProcessTest extends TestCase {

  use ProcessTrait;

  protected function setUp(): void {
    // Working directory, NULL for the current PHP process directory.
    $this->processCwd = NULL;
    // Whether to stream the output while the process runs.
    $this->processStreamingOutput = FALSE;
  }

  protected function tearDown(): void {
    // Stop the process if it is still running.
    $this->processTearDown();
  }

  public function testCommandExecution(): void {
    // Run a command with arguments, inputs, environment variables and
    // timeouts. The command name is validated, and every argument must
    // be scalar. An environment variable set to FALSE is removed from
    // the inherited environment.
    $process = $this->processRun(
      // Command to execute, optionally with arguments.
      'echo',
      // Additional command arguments.
      ['Hello', 'World'],
      // Inputs for an interactive process.
      ['Input1', 'Input2'],
      // Additional environment variables.
      ['ENV_VAR' => 'value'],
      // Process timeout in seconds.
      60,
      // Process idle timeout in seconds.
      30
    );

    // The most recent process is also available on demand.
    $process = $this->processGet();

    // Assert on the exit code.
    $this->assertProcessSuccessful();
    $this->assertProcessFailed();

    // Assert that the output contains string(s).
    $this->assertProcessOutputContains('Hello World');
    $this->assertProcessOutputContains(['Hello', 'World']);
    $this->assertProcessOutputContains('Hello', 'Not found');

    // Assert that the output does not contain string(s).
    $this->assertProcessOutputNotContains('Error');
    $this->assertProcessOutputNotContains(['Error1', 'Error2']);

    // The same assertions are available for the error output.
    $this->assertProcessErrorOutputContains('Warning');
    $this->assertProcessErrorOutputNotContains('Critical');

    // And for the standard and error output combined.
    $this->assertProcessAnyOutputContains('In either output');
    $this->assertProcessAnyOutputNotContains('In neither output');

    // Assert several conditions in one call using prefixes. See the
    // StringTrait section for the full prefix reference.
    // Shortcut mode: no prefixes, all must be present as substrings.
    $this->assertProcessOutputContainsOrNot(['Hello', 'World']);

    // Mixed mode: if any string has a prefix, all of them must.
    $this->assertProcessOutputContainsOrNot(['* Hello', '! Error']);
    $this->assertProcessErrorOutputContainsOrNot(['* Warning']);
    $this->assertProcessAnyOutputContainsOrNot(['* Hello', '! Error']);

    // '+' and '-' compare against the whole trimmed output, so they
    // only make sense for a single-line output.
    $this->assertProcessOutputContainsOrNot([
      // The whole output must equal this.
      '+ Hello World',
    ]);
  }

}

use AlexSkrypnyk\PhpunitHelpers\Traits\SerializableClosureTrait;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

class MyClosureTest extends TestCase {

  use SerializableClosureTrait;

  #[DataProvider('dataProviderWithClosure')]
  public function testWithClosure($callback): void {
    // Unwrap the closure before using it.
    $callback = self::cu($callback);
    $this->assertEquals('ARGUMENT', $callback('argument'));
  }

  public static function dataProviderWithClosure(): array {
    return [
      'traditional' => [
        self::cw(function ($value) {
          return strtoupper($value);
        }),
      ],
      'arrow_function' => [
        self::cw(fn($value) => strtoupper($value)),
      ],
    ];
  }

}

use AlexSkrypnyk\PhpunitHelpers\Traits\ReflectionTrait;
use PHPUnit\Framework\TestCase;

class MyReflectionTest extends TestCase {

  use ReflectionTrait;

  public function testProtectedMethod(): void {
    $object = new SomeClass();

    // Call a protected method. Pass a class name instead of an object
    // to call a protected static method.
    $result = self::callProtectedMethod($object, 'protectedMethod', [
      'argument',
    ]);

    // Set a protected property value.
    self::setProtectedValue($object, 'protectedProperty', 'new value');

    // Get a protected property value.
    $value = self::getProtectedValue($object, 'protectedProperty');
  }

}

use AlexSkrypnyk\PhpunitHelpers\Traits\TuiTrait;
use PHPUnit\Framework\TestCase;

class MyTuiTest extends TestCase {

  use TuiTrait;

  public function testTuiInteraction(): void {
    // Define the default entries for all sets.
    $default_entries = [
      'answer1' => 'value1',
      // Replaced with the default value, an empty string by default.
      'answer2' => self::TUI_DEFAULT,
      'answer3' => 'value3',
      'answer4' => 'value4',
    ];

    // First entry set: use the default for 'answer1'.
    $entries_set1 = ['answer1' => self::TUI_DEFAULT] + $default_entries;
    $processed_entries = self::tuiEntries($entries_set1);

    // Process entries with a custom default value.
    $processed_entries = self::tuiEntries($entries_set1, 'custom');

    // Second entry set: skip 'answer2' so it is left out entirely.
    $entries_set2 = ['answer2' => self::TUI_SKIP] + $default_entries;
    $processed_entries = self::tuiEntries($entries_set2);

    // Convert entries to keystrokes for character-by-character input.
    $keystrokes = self::tuiKeystrokes($entries_set1);

    // Keystroke conversion with options.
    $keystrokes = self::tuiKeystrokes(
      // Entries to convert.
      $entries_set1,
      // Number of characters to clear before entering new text.
      3,
      // Accept key. Defaults to the Enter key.
      self::KEYS['TAB'],
      // Clear key. Defaults to the Backspace key.
      self::KEYS['BACKSPACE']
    );

    // Convert a single entry into its keystrokes.
    $split = self::tuiEntryToKeystroke('ab' . self::KEYS['ENTER']);

    // Special keys are available as constants.
    $up_key = self::KEYS['UP'];
    $enter_key = self::KEYS['ENTER'];
    $tab_key = self::KEYS['TAB'];
    $esc_key = self::KEYS['ESCAPE'];
    $ctrl_c = self::KEYS['CTRL_C'];
    $backspace = self::KEYS['BACKSPACE'];

    // Arrow keys are supported in more than one format.
    $up_arrow = self::KEYS['UP_ARROW'];

    // Yes and No entries are predefined and can be overridden.
    $yes = self::$tuiYes;
    $no = self::$tuiNo;

    // Check whether a value is, or contains, a special key.
    $is_key = self::tuiIsKey($enter_key);
    $has_key = self::tuiHasKey('abc' . $enter_key);
  }

}

use AlexSkrypnyk\PhpunitHelpers\Traits\StringTrait;
use PHPUnit\Framework\TestCase;

class MyStringTest extends TestCase {

  use StringTrait;

  public function testSimpleStringMatching(): void {
    $haystack = 'The quick brown fox jumps over the lazy dog';

    // Shortcut mode: all values must be present as substrings.
    $this->assertStringContainsOrNot($haystack, [
      'quick',
      'brown',
      'fox',
    ]);

    // Mixed mode: every value carries a prefix.
    $this->assertStringContainsOrNot($haystack, [
      // Present as a substring.
      '* brown',
      // Absent as an exact match of the whole haystack.
      '- slow',
      // Absent as a substring.
      '! elephant',
    ]);

    // '+' matches the whole haystack.
    $this->assertStringContainsOrNot('Hello', ['+ Hello']);

    // Matching is case-insensitive by default.
    $this->assertStringContainsOrNot('Hello WORLD', ['* world']);

    // Case-sensitive matching, with the defaults spelled out.
    $this->assertStringContainsOrNot(
      'Hello WORLD',
      ['* WORLD', '! world'],
      'Expected exact match for "%s" in haystack',
      'Expected substring "%s" in haystack',
      'Expected no exact match for "%s" in haystack',
      'Expected substring "%s" not in haystack',
      // Prefixes: present exact, present contains, absent exact,
      // absent contains.
      '+', '*', '-', '!',
      // Separator between the prefix and the value.
      ' ',
      // Case-insensitive matching, turned off here.
      FALSE
    );

    // Custom prefixes.
    $this->assertStringContainsOrNot(
      $haystack,
      ['~ brown', '_ slow', '? elephant'],
      'Expected exact match for "%s" in haystack',
      'Expected substring "%s" in haystack',
      'Expected no exact match for "%s" in haystack',
      'Expected substring "%s" not in haystack',
      // Present exact.
      '#',
      // Present contains.
      '~',
      // Absent exact.
      '_',
      // Absent contains.
      '?'
    );
  }

}

use AlexSkrypnyk\PhpunitHelpers\Traits\LoggerTrait;
use PHPUnit\Framework\TestCase;

class MyLoggerTest extends TestCase {

  use LoggerTrait;

  protected function setUp(): void {
    static::logSetVerbose(TRUE);
  }

  public function testHierarchicalWorkflow(): void {
    static::log('Basic debug message');
    static::logSection('SECTION TITLE', 'Section content');
    static::logFile('/path/to/file.txt', 'Optional description');

    // Step tracking with automatic timing. The step name is taken from
    // the calling method, so the argument is only a message.
    static::logStepStart('Optional step message');
    static::logSubstep('Processing data');
    static::logNote('Additional context information');

    // A step started inside another step nests below it.
    $this->stepNested();

    static::logStepFinish('Step completed successfully');

    // logStepSummary() returns the table rather than printing it.
    static::logSection('WORKFLOW SUMMARY', static::logStepSummary(), TRUE, 80);
  }

  protected function stepNested(): void {
    static::logStepStart('Nested operation');
    static::logStepFinish('Nested operation complete');
  }

}

use AlexSkrypnyk\PhpunitHelpers\Traits\ApplicationTrait;
use AlexSkrypnyk\PhpunitHelpers\Traits\AssertArrayTrait;
use AlexSkrypnyk\PhpunitHelpers\Traits\EnvTrait;
use AlexSkrypnyk\PhpunitHelpers\Traits\LoggerTrait;
use AlexSkrypnyk\PhpunitHelpers\Traits\ProcessTrait;
use AlexSkrypnyk\PhpunitHelpers\Traits\ReflectionTrait;
use AlexSkrypnyk\PhpunitHelpers\Traits\TuiTrait;
use PHPUnit\Framework\TestCase;

class MyCombinedTest extends TestCase {

  use ApplicationTrait;
  use AssertArrayTrait;
  use EnvTrait;
  use LoggerTrait;
  // ApplicationTrait and ProcessTrait both 

use AlexSkrypnyk\PhpunitHelpers\Traits\EnvTrait;
use AlexSkrypnyk\PhpunitHelpers\UnitTestCase;

class MyTest extends UnitTestCase {

  // Add further traits as needed.
  use EnvTrait;

  // Your test methods.

}