Git Product home page Git Product logo

phantestic's Introduction

elazar/phantestic

A small PHP testing framework that aims to be simple, fast, modern, and flexible.

Currently in a very alpha state. Feel free to mess around with it, but expect things to break.

Build Status Code Climate

Installation

Use Composer.

{
    "require-dev": {
        "elazar/phantestic": "^0.2"
    }
}

Components

A test loader loads the tests to be run. It can be anything that implements \Traversable (i.e. an instance of a class that implements \IteratorAggregate or \Iterator, such as \Generator) to allow loaded tests to be iterable.

The test runner uses the test loader to load tests, run them, and in the process emit multiple events that test handlers can intercept and act upon.

As an example, LocalTestRunner runs tests in the same PHP process as the test runner. Its constructor accepts two arguments: the test loader to use and an array of test handler objects that implement TestHandlerInterface.

When its run() method is called, LocalTestRunner handles injecting an event emitter into the test handler objects, which enables those objects to register callbacks with the emitter for any events that may be relevant to them.

An example of a test handler is CliOutputTestHandler, which outputs the results of executing tests to stdout as they are received and a failure summary once all tests have been run.

Configuring a Runner

There is no stock test runner; one must be configured based on the needs of your project.

Here's a sample runner configuration.

$classmap_path = '../vendor/composer/autoload_classmap.php';
$loader = new \Phantestic\TestLoader\ClassmapFileObjectTestLoader($classmap_path);
$handlers = [ new \Phantestic\TestHandler\CliOutputTestHandler ];
$runner = new \Phantestic\TestRunner\LocalTestRunner($loader, $handlers);
$runner->run();

ClassmapFileObjectTestLoader locates tests based on the contents of a classmap file, such as the one generated by the -o flag of several Composer commands. By default, it looks for class files with names ending in Test.php, instantiates the classes, and invokes methods with names prefixed with test. Callbacks used to filter test methods based on file, class, and method names and to generate test case objects can be changed using the constructor parameters of ClassmapFileObjectTestLoader.

Writing Tests

Theoretically, tests can be anything callable. The test loader may restrict this to specific types of callables (e.g. ClassmapFileObjectTestLoader only supports instance methods). The test loader wraps test callbacks in an instance of a class implementing TestCaseInterface, such as the default TestCase implementation.

Failures can be indicated by throwing an exception. Other statuses can be indicated by throwing an instance of a subclass of TestResult. TestCase converts errors to exceptions and considers any uncaught exception to indicate failure. Likewise, no exception being thrown indicates success.

// src/Adder.php
class Adder
{
    public function add($x, $y)
    {
        return $x + $y;
    }
}

// tests/AdderTest.php
class AdderTest
{
    public function testAdd()
    {
        $adder = new Adder;
        $result = $adder->add(2, 2);
        if ($result != 4) {
            throw new \RangeException('2 + 2 should equal 4');
        }
    }
}

Writing Test Handlers

Test handlers implement TestHandlerInterface, which has a single method: setEventEmitter(). This method receives an instance of EventEmitterInterface as its only argument. Within its implementation of setEventEmitter(), a test handler can use this argument to register event callbacks. An example of this is below, taken from CliOutputTestHandler, which registers its own methods as callbacks for several events.

public function setEventEmitter(EventEmitterInterface $emitter)
{
    $emitter->on('phantestic.test.failresult', [$this, 'handleFail']);
    $emitter->on('phantestic.test.passresult', [$this, 'handlePass']);
    $emitter->on('phantestic.tests.before', [$this, 'beforeTests']);
    $emitter->on('phantestic.tests.after', [$this, 'afterTests']);
}

Supported events may vary depending on the test loader and runner in use.

  • phantestic.tests.before: Before any tests are run, with the test runner as an argument
  • phantestic.tests.after: After all tests are run, with the test runner as an argument
  • phantestic.test.before: Before each test, with the test case and runner as arguments
  • phantestic.test.after: After each test, with the test case and runner as arguments
  • phantestic.test.failresult: When a test fails, with the test case and runner as arguments
  • phantestic.test.passresult: When a test passes, with the test case and runner as arguments
  • phantestic.test.RESULT: When a test has a result other than passing or failing where RESULT is the short name of the class extending TestResult, with the test case and runner as arguments
  • phantestic.loader.loaded: When a test case is loaded, with the test case and associated test class name and test method name as arguments

Differences from PHPUnit

Tests may be instance methods of classes, but they don't have to be since individual tests can be anything callable. If you do choose to use instance methods for tests:

  • There is no equivalent to PHPUnit_Framework_TestCase. You may create your own base class if you wish, but it is not required.
  • There are no equivalents to setUp() or tearDown(). Consider using either __construct() and __destruct() or test handlers in conjunction with a loader that supports phantestic.test.before and phantestic.test.after.
  • If you wish for tests to be located using the same criteria as PHPUnit and you're using Composer, just use ClassmapFileObjectTestLoader and specify only the classmap file path when instantiating it.
  • Assertions are merely methods that throw exceptions if expected conditions are not met. Consider supplementary libraries.
  • Mocking is not supported natively. Consider supplementary libraries like Phake or Mockery.
  • Database seeding and assertions are not supported natively. Consider supplementary libraries like Phactory or Faker.

phantestic's People

Contributors

elazar avatar leftees avatar robertology avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.