An effort to make testing PHP code as easy and fun as its JavaScript equivalent

Related tags

Testing physalis
Overview

Build Status
endorse

Physalis

An effort to make testing PHP code as easy and fun as its JavaScript equivalent when using the excellent Jasmine, from which syntax and general usage is shamelessly borrowed.

System Requirements

Physalis requires PHP 5.4.x or later to run due to the heavy use of function closures.

Installation

Using Composer

Using composer is probably the easiest way. Just execute the following in your project folder:

$ composer require neochrome/physalis

or

$ php composer.phar require neochrome/physalis

if you don't have composer installed globally. This will pull the latest version from packagist and put it into your vendor folder. It will also create a symlink to the executable script as vendor/bin/physalis.

From source

Clone the repo or download the latest source and put in into your vendor folder. The executable script is in bin/.

Basic usage

Start off by describing something with a set of specifications, i.e how it should behave:


require_once 'calc.php';

describe('calculator', function () {
	$calc;
	beforeEach(function () use (&$calc) {
		$calc = new Calculator();
	});

	describe('adds', function () use (&$calc) {
		it('positive numbers', function () use (&$calc) {
			expect($calc->add(1, 2))->toBe(3);
		});

		it('negative numbers', function () use (&$calc) {
			expect($calc->add(-4, -5))->toBe(-9);
		});

		it('with zero', function () use (&$calc) {
			expect($calc->add(0, 10))->toBe(10);
		});
	});
	
	describe('divides', function () use (&$calc) {
		it('positive numbers', function () use (&$calc) {
			expect($calc->div(8, 2))->toBe(4);
		});

		it('throws on division by zero', function () use (&$calc) {
			expect(function () use (&$calc) { $calc->div(1, 0); })->toThrow();
		});
	});
});
?>

By default Physalis will pick up specifications from files named *.spec.php in subfolder spec. This may be overridden from the command line using the --specs switch. To verify the specifications, execute:

$ vendor/bin/physalis --specs=path/to/my/specs/*.spec.php

Contexts

Contexts contain specs and possible nested contexts. They are defined using the describe function with a description and a nested function scope/closure.

describe('a context', function () {
	// specs goes here
});

Specs

Specs are defined in a context using the it function with a description and a nested function/closure which sets up expectations.

it('has a certain behaviour', function () {
	// code setup and expectations goes here
});

Expectations

Expectations are boolean assertions that are built using the expect function with an actual value and then chained with a matcher function that will perform the assertion. Expectations may be negated by chaining with the not property, in which case the outcome of the following matcher function will be inverted.

it('is negated', function () {
	expect(false)->not->toBe(true);
});

Matchers

Matchers performs boolean comparisons of actual and expected values. Included matchers are:

toBe

Performs a strict comparison of actual and expected.

expect(42)->toBe(42);   // true
expect('42')->toBe(42); // false

toEqual

Performs a "loose" comparison of actual and expected.

expect(42)->toEqual(42);   // true
expect('42')->toEqual(42); // true

toMatch

Assumes expected to be a perl regular expression and tests if actual is a match.

expect('aBBa')->toMatch('/B+/'); // true

toContain

Assumes actual to be either a string or an array. Checks if it contains expected as a substring or an element respectively.

expect('hello world')->toContain('hello'); // true
expect([1, 2, 3])->toContain(2);           // true

toBeEmpty()

Assumes actual to be either a string or an array. Checks if it's empty.

expect('')->toBeEmpty(); // true
expect([])->toBeEmpty(); // true

toBeOfType

Checks if the type of actual is of the expected type (standard type or class).

expect(13)->toBeOfType('integer');                // true
expect(new Exception())->toBeOfType('Exception'); // true 

toThrow

Assumes actual to be callable, i.e function closure. Verifies that an exception is thrown when calling actual. If expected is given, checks that the thrown exception matches the expected.

expect(function () { throw new Exception(); })->toThrow('Exception'); // true

Custom matchers

Custom matchers may be created and registered in beforEach blocks by calling the $this->addMatchers function with an associative array where the keys are the matcher name and the values are the matcher function implementation.

Matcher functions should return true if a match, otherwise false. Actual and expected values are available through the properties $this->actual and $this->expected. By default a failing expectation will construct a message from the current actual and expected values together with the matcher name.

Custom messages may be specified by setting the property $this->message to an array with two functions returning strings. The first is the regular message and the second is the inverted message (when the expectation is negated).

An example:

actual > $this->expected; } ]); });">
beforeEach(function () {
	$this->addMatchers([
		'toBeGreaterThan' => function () {
			$actual = static::pp($this->actual); 
			$expected = static::pp($this->expected); 
			$this->message = [
				function () { return "Expected {$actual} to be greater than {$expected}"; },
				function () { return "Expected {$actual} not to be greater than {$expected}"; }
			];
			return $this->actual > $this->expected;
		}
	]);
});

beforeEach / afterEach

Each context may specify any number of beforeEach and afterEach function blocks. All before blocks are executed in order (outside and in) before each spec and may be used to perform common setup and or register new matchers. After blocks are executed in opposite order (inside and out) after each spec and may be used to perform common teardown etc.

Excluding contexts and specs

By using the xdescribe and xit functions, contexts and specs may be excluded (ignored) and won't affect the result.

Reporting results

By default Physalis will make use of the ProgressReporter which will output progress in a condensed form. Besides the ProgressReporter Physalis comes with a DocumentReporter which will output the full structure of all contexts and specs, as well as any failing expectations. To specify which reporter to use, supply the --reporter command line switch:

$ vendor/bin/physalis --reporter=DocumentReporter

Integration with other tools

Physalis will return an exit code of zero when all specs has passed, otherwise non-zero. This may be used as a step in a CI build to execute the specs continuously on each commit.

Final notes

If you find the tool useful, please feel free to star the repo, fork it and create pull requests or register issues with new ideas or things to fix. Most important however - have fun testing your PHP code!

You might also like...
Unit testing tips by examples in PHP

Unit testing tips by examples in PHP Introduction In these times, the benefits of writing unit tests are huge. I think that most of the recently start

Pest is an elegant PHP Testing Framework with a focus on simplicity
Pest is an elegant PHP Testing Framework with a focus on simplicity

Pest is an elegant PHP Testing Framework with a focus on simplicity. It was carefully crafted to bring the joy of testing to PHP. Explore the docs: pe

PHPArch is a work in progress architectural testing library for PHP projects

PHPArch What is this? Installation Simple Namespace validation Available Validators Defining an architecture Syntactic sugar: Bulk definition of compo

Humbug - a Mutation Testing framework for PHP

Humbug is a Mutation Testing framework for PHP to measure the real effectiveness of your test suites and assist in their improvement. It eats Code Coverage for breakfast.

:computer: Parallel testing for PHPUnit

ParaTest The objective of ParaTest is to support parallel testing in PHPUnit. Provided you have well-written PHPUnit tests, you can drop paratest in y

Few additional testing assertions for Laravel views

Laravel View Test Assertions Few additional assertions for testing Laravel views. Why Laravel has well established and documented way of testing reque

Real-world Project to learning about Unit Testing/TDD with Laravel for everybody

KivaNote - a Laravel TDD Sample Project Let me introduce you to KivaNote, a simple real-world application using Laravel to show you how the TDD & Unit

Package for unit testing Laravel form request classes
Package for unit testing Laravel form request classes

Package for unit testing Laravel form request classes. Why Colin DeCarlo gave a talk on Laracon online 21 about unit testing Laravel form requests cla

Magic Test allows you to write browser tests by simply clicking around on the application being tested, all without the slowness of constantly restarting the testing environment.

Magic Test for Laravel Magic Test allows you to write browser tests by simply clicking around on the application being tested, all without the slownes

Comments
  • Fix typographical error(s)

    Fix typographical error(s)

    @neochrome, I've corrected a typographical error in the documentation of the physalis project. Specifically, I've changed comparision to comparison. You should be able to merge this pull request automatically. However, if this was intentional or if you enjoy living in linguistic squalor, please let me know and create an issue on my home repository.

    opened by orthographic-pedant 1
Owner
Johan Stenqvist
Johan Stenqvist
SimpleTest is a framework for unit testing, web site testing and mock objects for PHP

SimpleTest SimpleTest is a framework for unit testing, web site testing and mock objects for PHP. Installation Downloads All downloads are stored on G

SimpleTest 147 Jun 20, 2022
PHP libraries that makes Selenium WebDriver + PHPUnit functional testing easy and robust

Steward: easy and robust testing with Selenium WebDriver + PHPUnit Steward is a set of libraries made to simplify writing and running robust functiona

LMC s.r.o. 219 Dec 17, 2022
CommandHelper - is a very useful thing for quick code testing and more!

CommandHelper CommandHelper - is a very useful thing for quick code testing and more! Examples: Code: require_once('commandhelper.php');

RuvSleep 1 Feb 11, 2022
Infrastructure and testing helpers for creating CQRS and event sourced applications.

Broadway is a project providing infrastructure and testing helpers for creating CQRS and event sourced applications. Broadway tries hard to not get in your way.

null 1.5k Dec 30, 2022
The modern, simple and intuitive PHP unit testing framework.

atoum PHP version atoum version 5.3 -> 5.6 1.x -> 3.x 7.2 -> 8.x 4.x (current) A simple, modern and intuitive unit testing framework for PHP! Just lik

atoum 1.4k Nov 29, 2022
PHP unit testing framework with built in mocks and stubs. Runs in the browser, or via the command line.

Enhance PHP A unit testing framework with mocks and stubs. Built for PHP, in PHP! Quick Start: Just add EnhanceTestFramework.php and you are ready to

Enhance PHP 67 Sep 12, 2022
The Phoronix Test Suite is the most comprehensive testing and benchmarking platform

The Phoronix Test Suite is the most comprehensive testing and benchmarking platform available for Linux, Solaris, macOS, Windows, and BSD operating systems.

Phoronix Test Suite 1.9k Jan 7, 2023
Full-stack testing PHP framework

Codeception Modern PHP Testing for everyone Codeception is a modern full-stack testing framework for PHP. Inspired by BDD, it provides an absolutely n

Codeception Testing Framework 4.6k Jan 7, 2023
AST based PHP Mutation Testing Framework

Infection - Mutation Testing framework Please read documentation here: infection.github.io Twitter: @infection_php Discord: https://discord.gg/ZUmyHTJ

Infection - Mutation Testing Framework for PHP 1.8k Jan 2, 2023
The PHP Unit Testing framework.

PHPUnit PHPUnit is a programmer-oriented testing framework for PHP. It is an instance of the xUnit architecture for unit testing frameworks. Installat

Sebastian Bergmann 18.8k Jan 4, 2023