ciarand / pho
Requires
- php: >=5.4.0
This package is not auto-updated.
Last update: 2024-09-24 05:10:46 UTC
README
该项目已弃用且不再维护。请谨慎操作!
PHP的BDD测试框架,灵感来源于Jasmine和RSpec。正在开发中。欢迎提出功能请求和拉取请求!
安装
以下说明使用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个函数来组织和编写测试:describe
、context
、it
、before
、after
、beforeEach
、afterEach
和expect
。
要创建一个测试套件,可以使用describe
和context
,将它们传递一个字符串和函数。两者可以互换,尽管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'); });
可以使用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
在套件中的所有规范运行后运行。beforeEach
和afterEach
在每个规范上都运行一次它们的闭包。请注意,beforeEach
和afterEach
都是可堆叠的,并将应用于嵌套套件中的规范。
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在当前工作目录下的test
或spec
文件夹中查找规范。它会递归遍历所有子文件夹并运行所有以Spec.php
结尾的文件,例如:userSpec.php。此外,使用--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目前不提供开箱即用的模拟/存根。相反,建议使用模拟框架,如prophecy或mockery。
命名空间
如果您不想让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