ciarand/pho

基于BDD测试框架的分支

1.0.0 2013-12-08 02:57 UTC

This package is not auto-updated.

Last update: 2024-09-24 05:10:46 UTC


README

该项目已弃用且不再维护。请谨慎操作!

pho

PHP的BDD测试框架,灵感来源于Jasmine和RSpec。正在开发中。欢迎提出功能请求和拉取请求!

Build Status

安装

以下说明使用Composer进行安装。如果您没有Composer,可以从http://getcomposer.org/下载。

  • 根据您的环境运行以下任意一个命令
$ composer global require danielstjules/pho:dev-master
$ php composer.phar global require danielstjules/pho:dev-master
  • 编辑您的~/.bash_profile~/.profile并添加
export PATH=$HOME/.composer/vendor/bin:$PATH

编写规范

Pho提供了8个函数来组织和编写测试:describecontextitbeforeafterbeforeEachafterEachexpect

要创建一个测试套件,可以使用describecontext,将它们传递一个字符串和函数。两者可以互换,尽管context更常嵌套在describe中以分组某些行为。然后使用it创建规范或测试。

规范可以包含多个期望或断言,只要所有断言都通过且没有未捕获的异常,它就会通过。在Pho中,可以使用expect来断言值。该函数接受要测试的值,可以与一些匹配器链式使用。

<?php

describe('A suite', function() {
    it('contains specs with expectations', function() {
        expect(true)->toBe(true);
    });

    it('can have specs that fail', function() {
        expect(false)->not()->toBe(false);
    });

    it('can have incomplete specs');
});

intro-screenshot

可以使用PHP的use关键字在测试套件和规范之间传递对象。以下是一个示例

describe('Example', function() {
    $object = new stdClass();
    $object->name = 'pho';

    context('name', function() use ($object) {
        it('is set to pho', function()  use ($object) {
            expect($object->name)->toBe('pho');
        });
    });
});

当需要将多个对象传递到使用use的闭包时,事情可能会变得有点冗长。为了避免如此长的参数列表,可以使用$this在测试套件和规范之间设置和检索值。

describe('SomeClass', function() {
    $this->key1 = 'initialValue';
    $this->key2 = 'initialValue';

    context('methodOne()', function() {
        $this->key1 = 'changedValue';

        it('contains a spec', function() {
            expect($this->key1)->toBe('changedValue');
            expect($this->key2)->toBe('initialValue');
        });
    });

    context('methodTwo()', function() {
        it('contains another spec', function() {
            expect($this->key1)->toBe('initialValue');
            expect($this->key2)->toBe('initialValue');
        });
    });
});

提供了挂钩,用于在设置和拆卸时运行函数。before在套件中的任何规范之前运行,而after在套件中的所有规范运行后运行。beforeEachafterEach在每个规范上都运行一次它们的闭包。请注意,beforeEachafterEach都是可堆叠的,并将应用于嵌套套件中的规范。

describe('Suite with Hooks', function() {
    $this->count = 0;

    beforeEach(function() {
        $this->count = $this->count + 1;
    });

    it('has a count equal to 1', function() {
        expect($this->count)->toEqual(1);
        // A single beforeEach ran
    });

    context('nested suite', function() {
        beforeEach(function() {
            $this->count = $this->count + 1;
        });

        it('has a count equal to 3', function() {
            expect($this->count)->toEqual(3);
            // Both beforeEach closures incremented the value
        });
    });
});

运行规范

默认情况下,Pho在当前工作目录下的testspec文件夹中查找规范。它会递归遍历所有子文件夹并运行所有以Spec.php结尾的文件,例如:userSpec.php。此外,使用--watch选项进行持续测试非常简单,该选项将监视路径中的所有文件,并在保存时重新运行规范。

watch

期望/匹配器

类型匹配

expect('pho')->toBeA('string');
expect(1)->notToBeA('string');
expect(1)->not()->toBeA('string');

expect(1)->toBeAn('integer'); // Alias for toBeA
expect('pho')->notToBeAn('integer');
expect('pho')->not()->toBeA('integer');

实例匹配

expect(new User())->toBeAnInstanceOf('User');
expect(new User())->not()->toBeAnInstanceOf('Post');
expect(new User())->notToBeAnInstanceOf('Post');

严格相等匹配

expect(1)->toBe(1);
expect(1)->not()->toBe(2);
expect(1)->notToBe(2);

expect(['foo'])->toEqual(['foo']); // Alias for toBe
expect(['foo'])->not()->toEqual(true);
expect(['foo'])->notToEqual(true);

expect(null)->toBeNull();
expect('pho')->not()->toBeNull();
expect('pho')->notToBeNull();

expect(true)->toBeTrue();
expect(1)->not()->toBeTrue();
expect(1)->notToBeTrue();

expect(false)->toBeFalse();
expect(0)->not()->toBeFalse();
expect(0)->notToBeFalse();

宽松相等匹配

expect(1)->toEql(true);
expect(new User('Bob'))->not()->ToEql(new User('Alice'))
expect(new User('Bob'))->notToEql(new User('Alice'))

长度匹配

expect(['tdd', 'bdd'])->toHaveLength(2);
expect('pho')->not()->toHaveLength(2);
expect('pho')->notToHaveLength(2);

expect([])->toBeEmpty();
expect('pho')->not()->toBeEmpty();
expect('pho')->notToBeEmpty();

包含匹配

expect('Spectacular!')->toContain('Spec');
expect(['a', 'b'])->not()->toContain('c');
expect(['a', 'b'])->notToContain('c');

expect('testing')->toContain('test', 'ing'); // Accepts multiple args
expect(['tdd', 'test'])->not()->toContain('bdd', 'spec');
expect(['tdd', 'test'])->notToContain('bdd', 'spec');

expect('testing')->toContainAnyOf('test', 'spec');
expect(['tdd', 'test'])->not()->toContainAnyOf('bdd', 'test');
expect(['tdd', 'test'])->notToContainAnyOf('bdd', 'test');

expect(['name' => 'pho'])->toHaveKey('name');
expect(['name' => 'pho'])->not()->toHaveKey('id');
expect(['name' => 'pho'])->notToHaveKey('id');

模式匹配

expect('tdd')->toMatch('/\w[D]{2}/i');
expect('pho')->not()->toMatch('/\d+/');
expect('pho')->notToMatch('/\d+/');

expect('username')->toStartWith('user');
expect('spec')->not()->toStartWith('test');
expect('spec')->notToStartWith('test');

expect('username')->toEndWith('name');
expect('spec')->not()->toEndWith('s');
expect('spec')->notToEndtWith('s');

数字匹配

expect(2)->toBeGreaterThan(1);
expect(2)->not()->toBeGreaterThan(2);
expect(1)->notToBeGreaterThan(2);

expect(2)->toBeAbove(1); // Alias for toBeGreaterThan
expect(2)->not()->toBeAbove(2);
expect(1)->notToBeAbove(2);

expect(1)->toBeLessThan(2);
expect(1)->not()->toBeLessThan(1);
expect(2)->notToBeLessThan(1);

expect(1)->toBeBelow(2); // Alias for toBeLessThan
expect(1)->not()->toBeBelow(1);
expect(2)->notToBeBelow(1);

expect(1)->toBeWithin(1, 10); // Inclusive
expect(-2)->not()->toBeWithin(-1, 0);
expect(-2)->notToBeWithin(-1, 0);

打印匹配

$callable = function() {
  echo 'test'
};

expect($callable)->toPrint('test');
expect($callable)->not()->toPrint('testing');
expect($callable)->notToPrint('testing');

异常匹配

$callable = function() {
  throw new Custom\Exception('error!');
};

expect($callable)->toThrow('Custom\Exception');
expect($callable)->not()->toThrow('\ErrorException');
expect($callable)->notToThrow('\ErrorException');

报告器

点(默认)

$ pho --reporter dot exampleSpec.php

.FI

Failures:

"A suite can have specs that fail" FAILED
/Users/danielstjules/Desktop/exampleSpec.php:9
Expected false not to be false

Finished in 0.00125 seconds

3 specs, 1 failure, 1 incomplete

spec

$ pho --reporter spec exampleSpec.php

A suite
    contains specs with expectations
    can have specs that fail
    can have incomplete specs

Failures:

"A suite can have specs that fail" FAILED
/Users/danielstjules/Desktop/exampleSpec.php:9
Expected false not to be false

Finished in 0.0012 seconds

3 specs, 1 failure, 1 incomplete

列表

$ pho --reporter list exampleSpec.php

A suite contains specs with expectations
A suite can have specs that fail
A suite can have incomplete specs

Failures:

"A suite can have specs that fail" FAILED
/Users/danielstjules/Desktop/exampleSpec.php:9
Expected false not to be false

Finished in 0.0012 seconds

3 specs, 1 failure, 1 incomplete

模拟

Pho目前不提供开箱即用的模拟/存根。相反,建议使用模拟框架,如prophecymockery

命名空间

如果您不想让Pho使用全局命名空间来使用其函数,可以将--namespace标志设置为强制它只使用Pho命名空间。这将是在PHP 5.6中使用https://wiki.php.net/rfc/use_function的一个更佳选择。

pho\describe('A suite', function() {
    pho\it('contains specs with expectations', function() {
        pho\expect(true)->toBe(true);
    });

    pho\it('can have specs that fail', function() {
        pho\expect(false)->not()->toBe(false);
    });
});

选项

$ bin/pho --help
Usage: pho [options] [files]

Options

   -a   --ascii                   Show ASCII art on completion
   -h   --help                    Output usage information
   -f   --filter      <pattern>   Run specs containing a pattern
   -r   --reporter    <name>      Specify the reporter to use
   -s   --stop                    Stop on failure
   -v   --version                 Display version number
   -w   --watch                   Watch files for changes and rerun specs
   -n   --namespace               Only use namespaced functions