Coder Social home page Coder Social logo

matura's Introduction

Matura

![Gitter](https://badges.gitter.im/Join Chat.svg) Build Status

An RSpec / Mocha inspired testing tool for php. Requires 5.3+.


Installation

  1. composer require "jacobstr/matura ~0.2"

Features

  • Esperance expectation library: expect($result)->to->have->length(2).

  • A succinct DSL for defining tests.

     	describe('Matura', function ($ctx){
     		it('should make writing tests fun', function ($ctx) {
     			expect($are_we_having_fun_yet)->to->eql(true);
     		});
     	});
  • Heirarchical blocks to drill down from basic to complex assertions.

     	describe('User', function ($ctx) {
     		describe('Authorization', function ($ctx){
     			describe('OAuth', function ($ctx) {});
     		});
     	});
  • before, before_all, after, after_all, hooks with a well-defined ordering.

     	describe('User Database', function ($ctx) {
     		foreach(range(1,5) as $repetition) {
      			it('should insert a user', function ($ctx){
      				$user = $ctx->db->findOne(array(
      					'username' => $ctx->username;
      				));
      				expect($user)->to->have->length(1);
      			});
    
      			it('should not accumulate users', function ($ctx){
      				$users = $ctx->db->find();
      				expect($users)->to->have->length(1);
      			});
     		}
    
     		// Executed once for each describe block.
     		before_all(function ($ctx){
     			$ctx->test_id = uniqid();
     			$ctx->test_db = 'DB_'.$ctx->test_id;
     			$ctx->db = new Database('localhost', $ctx->test_db);
     		});
    
     		// Executed prior to each test (including descendants).
     		before(function ($ctx){
     		 	$ctx->username = 'test_user'.$ctx->test_id.uniqid();
     			$ctx->db->insert(array('username' => $ctx->username)); 
     		});
    
     		// Executed after each test (including descendants);
     		after(function ($ctx) {
     			$ctx->db->delete(array('username' => $ctx->username));
     		});
    
     		// Executed once at the very end of this describe block.
     		after_all(function ($ctx) {
     			$ctx->db->drop($ctx->test_db);
     		});
     	});

Assertions

As mentioned above, Matura uses Esperance as it's assertion library. Here are the core examples that you can use:

	// Deep Equal(===)
	expect($object)->to->be($cloned_object);
	// Approximately Equal(==)
	expect($object)->to->eql(NULL);
	// Not Equal/Be/A
	expect($object)->to->not->be('Walrus')
	// Type Checking
	expect($object)->to->be->a('AwesomeObject');
	expect($object)->to->be->an('AwesomeObject');
	// Truthy
	expect($success)->to->be->ok();
	// Invokability
	expect($example_func)->to->be->invokable();
	// Range Checking
	expect($number)->to->be->within($start, $finish);
	// Above
	expect($number)->to->be->above($floor);
	// Below
	expect($number)->to->be->below($ceiling);
	// Empty
	expecy($an_array)->to->be->empty();
	// Grep
	expect($greppable)->to->match($regexp);
	// Exception/Error Throwing
	expect($function)->to->throw($klass, $expected_msg);
	// Length
	expect('bob')->to->have->length(3);
	// Complex Assertions
	expect($complex)->to->not->be('Simple')->and->to->be('Complex');

The CLI

If you run, bin/mat test test/examples:

Matura Shell Output

And the documentation for the standard test command:

Usage:
test [-g|--grep="..."] [-i|--include="..."] [-x|--exclude="..."] [-d|--trace_depth="..."] path

Arguments:
 path                  The path to the file or directory to test.

Options:
 --grep (-g)           Filter individual test cases by a description regexp.
 --include (-i)        Include test files by a basename(filename) regexp.
 --exclude (-x)        Exclude test files by a basename(filename) regexp.
 --trace_depth (-d)    Set the depth of printed stack traces.
 --help (-h)           Display this help message.
 --quiet (-q)          Do not output any message.
 --verbose (-v|vv|vvv) Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
 --version (-V)        Display this application version.
 --ansi                Force ANSI output.
 --no-ansi             Disable ANSI output.
 --no-interaction (-n) Do not ask any interactive question.

Filtering

If you wish to filter specific tests within a suite/file, use --grep. Matura will be clever enough to run the requisite before/after hooks.

Test Result Association

When running before/after hooks Matura will associate any test failures with the currently running test, rather than treating it as a file-level failure. This is particularly useful with Mockery's close method, which triggers additional assertions: was a method called, was it called with the right parameters, and so on.

For before_all / after_all hooks, the failure is associate with the surrounding describe block.

Test Organization

By default, Matura filters on the file's basename for anything beginning with test_.

I'm using the structure below. I might formalize this some time:

├── test // Actual test cases.
│   ├── functional // Functional tests.
│   │   ├── test_context.php
│   │   ├── test_model.php
│   │   └── test_ordering.php
│   ├── integration // More end-to-end flavored tests.
│   │   └── test_test_runner.php
│   └── performance // Tests that serve to benchmark your code.
│       └── test_stress.php

I keep my fixtures in a top-level support folder. I've seen these placed in the test folder but I chose to keep them tucked away to avoid iterating over them and making the default filter complex.

Authoring Tests

The one key piece is you want to place your tests in the Matura\Tests namespace if you're not using PHP 5.6. If you're using 5.6 you can import the functions in Matura\Tests into your namespace.

Further Documentation

I swear it's not a cop out! Examine the tests folder.

TODOS

  • There's currently nothing like PHPUnit's backupGlobals. Maybe there shouldn't be - I feel a better way to find inadvertent coupling / dependencies on global variables may be to add functionality that randomizes test ordering.
  • Backtraces annoyingly include calls internal to the framework.
  • I'm a fan of contract tests. Class-based tests seem better suited to them, however, so I'm in need of inspiration wrt to the callback-driven dsl that matura uses. Maybe an invocable class...

Thanks!

  • Ben Zittlau - PHPUsable which brings similar syntax to PHPUnit. Helped me realize this was a worthwhile diversion.

matura's People

Contributors

jacobstr avatar derekdowling avatar gitter-badger avatar

Stargazers

Adam Halasz avatar Mindaugas Mačiulaitis avatar Paulo Romão avatar Andrea Sangiorgio avatar Andy Daniel Navarro Taño avatar Du Zhigang (ト シゴウ) avatar Osman Alpaydın avatar Jason Kelly avatar Alpha avatar Michael Sprague avatar Israel Santiago avatar Andrei Pascu avatar Guillem CANAL avatar Daniel Rosengren avatar martinp avatar Mohammed Irfan avatar Augustus Yuan avatar Nuruddin Ashr avatar Ely De La Cruz avatar Mark Holtz avatar Gabriel Mazetto avatar Esaú García Sánchez-Torija avatar Daijiro Wachi avatar Keith Humm avatar Julio Betta avatar  avatar Bruno Cassol avatar Brian Scaturro avatar Sergey Protko avatar Morgan Evans avatar Erin avatar Bursa avatar Hassen Ben Tanfous avatar Mark Bennett avatar  avatar

Watchers

Greg Bell avatar Mark Fossen avatar James Cloos avatar Esaú García Sánchez-Torija avatar Mallikarjuna avatar

matura's Issues

"Nesting level too deep"

When I run:

vendor/bin/mat test -i 'test_.*.php' -x 'test_php.*.php' test

Some tests run and then I get:

PHP Fatal error:  Nesting level too deep - recursive dependency? in /mover/backend/vendor/esperance/esperance/src/Esperance/Assertion.php on line 262
2014-11-29T01:18:26+00:00 ErrorHandler.php:62 « handleError « ErrorHandler.php:105 « handleFatalError « Array (
    [timestamp] => [29/Nov/2014:01:18:26 +0000]
    [type] => 1
    [location] => Array (
        [file] => /mover/backend/vendor/esperance/esperance/src/Esperance/Assertion.php
        [line] => 262
    )
    [message] => Nesting level too deep - recursive dependency?
    [context] => null
    [user] => Array (
        [uuid] => null
        [email] => null
        [session] => null
    )
)

on: test/Mover/API/Connector/test_controller.php

But if I run:

vendor/bin/mat test test/Mover/API/Connector/test_controller.php

Everything works just fine:

Running: test/Mover/API/Connector/test_controller.php

Connector API Controller Test
   ->emailAuthAction()
✓ 1) should return gracefully if a mode isnt specified
✓ 2) should return gracefull if no email is specified
      delegate authentication
✓ 3) should perform a successful delegate auth
      surrogate authentication
✓ 4) should perform a successful surrogate auth
✓ 5) should error gracefully if no surrogate specified

Passed: 5 of 5 Skipped: 0 Failed: 0 Assertions: 8

Consider to use $this instead of $ctx argument

I know that it will break compability wth php5.3 but hey... php5.3 is no longer supported.

Example:

describe('User Database', function () {
    foreach(range(1,5) as $repetition) {
        it('should insert a user', function (){
            $user = $this->db->findOne([
                'username' => $this->username;
            ]);
            expect($user)->to->have->length(1);
        });

        it('should not accumulate users', function (){
            $users = $this->db->find();
            expect($users)->to->have->length(1);
        });
    }
    // ...
}

This will allow to add mock injection into closures based on typehint (see phpspec implementation for example).

    before_all(function (Database $databaseMock) {
        $this->db = $databaseMock;
    });

Stream test output to file.

Detailed exception output doesn't occur until the end of the test run. Sometimes you want to stop test execution as soon as you notice failures with ctrl-c - but then you miss that detailed output at the very end.

One of my other solutions here is to simply stream the test results to a configurable data directory. Besides giving you historical information on local test runs, it will also capture the data gathered up until the point of failure.

It should be possible to play this back into the result printer. An interesting approach - instead of capturing the data as parsed by a particular reported, log the independent events. An interesting side effect is, given timestamps are injected, you could play back a test suite and get a feel for the 'dynamics' of your test execution. This matters more when you're doing things like API requests or expensive queries.

Don't fail on @-swallowed errors

I had some trouble when using Matura to test code in which I deliberately assign previously undefined indexes in an array, and use PHP's @-prefix method of suppressing the notices which result from doing so. Unfortunately, I found Matura still treats such suppressed notices as exceptions, and fails the tests in which they occur. Happily, the fix for this behavior was quite straightforward and uncomplicated; I've fixed it and added a test for the fix in aaron-em@90e45b3.

Issue With Composer Instructions

➜ clonker composer require jacobstr/matura
Please provide a version constraint for the jacobstr/matura requirement: dev
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

Problem 1
- The requested package jacobstr/matura dev could not be found.

Potential causes:

Read http://getcomposer.org/doc/articles/troubleshooting.md for further common problems.

Installation failed, reverting ./composer.json to its original content.

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.