我如何测试在我的 phpspec 测试中生成的东西的类型?
How can I test the type of something generated in my phpspec test?
例如:
测试代码
function it_records_last_checked()
{
$this->getWrappedObject()->setServiceLocator( $this->getServiceLocator() );
$this->isAvailable( 'google.com' )->shouldReturn( false );
/** @var Url $last */
$last = $this->getLastChecked();
$last->shoudHaveType( Url::class );
$last->host->registrableDomain->shouldBeLike('google.com');
}
规范包装了一个代码如下的对象:
namespace Application\Service;
use Application\Exception\DomainInvalidException;
use Application\Model\Whois;
use Pdp\Uri\Url;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorAwareTrait;
use Application\Exception\DomainRequiredException;
class DomainService implements ServiceLocatorAwareInterface{
use ServiceLocatorAwareTrait;
/** @var Url */
protected $last_checked;
/**
* @return Url
*/
public function getLastChecked()
{
return $this->last_checked;
}
/**
* @param Url $last_checked
*/
public function setLastChecked( $last_checked )
{
$this->last_checked = $last_checked;
}
/**
* Use available configuration to determine if a domain is available
* @param $domain
* @return bool
* @throws DomainRequiredException
* @throws \Exception
*/
public function isAvailable($domain)
{
if( !$domain )
throw new DomainRequiredException();
$pslManager = new \Pdp\PublicSuffixListManager();
$parser = new \Pdp\Parser($pslManager->getList());
$host = 'http://' . $domain;
if( !$parser->isSuffixValid( $host ) )
throw new DomainInvalidException();
$this->last_checked = $parser->parseUrl($host);
$whois = new Whois($this->last_checked->host->registerableDomain);
return $whois->isAvailable();
}
}
该服务设置其 last_checked 成员,例如我要测试其类型。它似乎不是 return 包装对象,它 return 是实际的 Pdp\Uri\Url 实例。
编写测试的规则是什么,以确保我们得到包装对象(主题)?
谢谢!
您在测试此逻辑时发现的困难是 PhpSpec 试图将您推向不同的设计。您的测试正在验证并依赖于 6/7 个其他对象的 behaviour/structure,使其更像是一个集成测试而不是单元测试(在 PhpSpec 中这样做是有意的困难)
我已经强调了其中一些依赖项:
<?php
public function isAvailable($domain)
{
// Pdp\Parser instantiation and configuration
$pslManager = new \Pdp\PublicSuffixListManager();
$parser = new \Pdp\Parser($pslManager->getList());
// Validation and parsing of $domain into an Url object
if( !$domain ) {
throw new DomainRequiredException();
}
$host = 'http://' . $domain;
if( !$parser->isSuffixValid( $host ) ) {
throw new DomainInvalidException();
}
$this->last_checked = $parser->parseUrl($host);
// The "isAvailable" check
// This depends on `Pdp\Uri\Url\Host` (in addition to Whois and `Pdp\Uri\Url`
$whois = new Whois($this->last_checked->host->registerableDomain);
return $whois->isAvailable();
}
通过移动 Pdp 类 的 configuration/instantiation,并将 validation/parsing 逻辑从 Whois
check 中分离出来,您可以快速得到更可测试的东西(不过用起来不太方便API)
public function __construct(\Pdp\Parser $parser)
{
$this->parser = $parser;
}
public function parseDomain($domain)
{
if( !$domain ) {
throw new DomainRequiredException();
}
$host = 'http://' . $domain;
if( !$parser->isSuffixValid( $host ) )
throw new DomainInvalidException();
return $parser->parseUrl($host);
}
public function isAvailable(Url $domain)
{
$whois = new Whois($domain->host->registerableDomain);
return $whois->isAvailable();
}
但是,通过让 Whois 能够检查您的 Url
对象是否可用,并注入它,测试变得更加容易
class DomainParser
{
// Pdp\Parser should be registered as a service
public function __construct(\Pdp\Parser $parser)
{
$this->parser = $parser;
}
public function parseDomain($domain)
{
if( !$domain ) {
throw new DomainRequiredException();
}
$host = 'http://' . $domain;
if( !$parser->isSuffixValid( $host ) )
throw new DomainInvalidException();
return $parser->parseUrl($host);
}
}
class Whois
{
public function isUrlAvailable(Url $url)
{
// Whois logic
}
}
class DomainService
{
public function __construct(DomainParser $parser, Whois $whois)
{
$this->parser = $parser;
$this->whois = $whois;
}
public function isAvailable($domain)
{
$url = $this->parser->parseDomain($domain);
$this->last_checked = $url;
return $this->whois->isUrlAvailable($url);
}
}
有了这三个类,很容易对DomainService
和DomainParser
进行单元测试,Whois
可以用另一种策略来模拟和测试(假设它与第三方系统)
例如
function let(DomainParser $parser, Whois $whois)
{
$this->beConstructedWith($parser, $whois);
}
function it_shows_a_domain_is_available(
DomainParser $parser,
Whois $whois,
Url $url
) {
$parser->parseDomain('http://test.com')->willReturn($url);
$whois->isUrlAvailable($url)->willReturn(true);
$this->isAvailable('http://test.com')->shouldReturn(true);
}
function it_records_last_checked(
DomainParser $parser,
Whois $whois,
Url $url
) {
$parser->parseDomain('http://test.com')->willReturn($url);
$whois->isUrlAvailable($url)->willReturn(true);
$this->isAvailable('http://test.com');
// Note that we don't validate any properties on Url, that is the
// responsibility of the tests for DomainParser and the Url object itself
$this->getLastChecked()->shouldReturn($url);
}
例如:
测试代码
function it_records_last_checked()
{
$this->getWrappedObject()->setServiceLocator( $this->getServiceLocator() );
$this->isAvailable( 'google.com' )->shouldReturn( false );
/** @var Url $last */
$last = $this->getLastChecked();
$last->shoudHaveType( Url::class );
$last->host->registrableDomain->shouldBeLike('google.com');
}
规范包装了一个代码如下的对象:
namespace Application\Service;
use Application\Exception\DomainInvalidException;
use Application\Model\Whois;
use Pdp\Uri\Url;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorAwareTrait;
use Application\Exception\DomainRequiredException;
class DomainService implements ServiceLocatorAwareInterface{
use ServiceLocatorAwareTrait;
/** @var Url */
protected $last_checked;
/**
* @return Url
*/
public function getLastChecked()
{
return $this->last_checked;
}
/**
* @param Url $last_checked
*/
public function setLastChecked( $last_checked )
{
$this->last_checked = $last_checked;
}
/**
* Use available configuration to determine if a domain is available
* @param $domain
* @return bool
* @throws DomainRequiredException
* @throws \Exception
*/
public function isAvailable($domain)
{
if( !$domain )
throw new DomainRequiredException();
$pslManager = new \Pdp\PublicSuffixListManager();
$parser = new \Pdp\Parser($pslManager->getList());
$host = 'http://' . $domain;
if( !$parser->isSuffixValid( $host ) )
throw new DomainInvalidException();
$this->last_checked = $parser->parseUrl($host);
$whois = new Whois($this->last_checked->host->registerableDomain);
return $whois->isAvailable();
}
}
该服务设置其 last_checked 成员,例如我要测试其类型。它似乎不是 return 包装对象,它 return 是实际的 Pdp\Uri\Url 实例。
编写测试的规则是什么,以确保我们得到包装对象(主题)?
谢谢!
您在测试此逻辑时发现的困难是 PhpSpec 试图将您推向不同的设计。您的测试正在验证并依赖于 6/7 个其他对象的 behaviour/structure,使其更像是一个集成测试而不是单元测试(在 PhpSpec 中这样做是有意的困难)
我已经强调了其中一些依赖项:
<?php
public function isAvailable($domain)
{
// Pdp\Parser instantiation and configuration
$pslManager = new \Pdp\PublicSuffixListManager();
$parser = new \Pdp\Parser($pslManager->getList());
// Validation and parsing of $domain into an Url object
if( !$domain ) {
throw new DomainRequiredException();
}
$host = 'http://' . $domain;
if( !$parser->isSuffixValid( $host ) ) {
throw new DomainInvalidException();
}
$this->last_checked = $parser->parseUrl($host);
// The "isAvailable" check
// This depends on `Pdp\Uri\Url\Host` (in addition to Whois and `Pdp\Uri\Url`
$whois = new Whois($this->last_checked->host->registerableDomain);
return $whois->isAvailable();
}
通过移动 Pdp 类 的 configuration/instantiation,并将 validation/parsing 逻辑从 Whois
check 中分离出来,您可以快速得到更可测试的东西(不过用起来不太方便API)
public function __construct(\Pdp\Parser $parser)
{
$this->parser = $parser;
}
public function parseDomain($domain)
{
if( !$domain ) {
throw new DomainRequiredException();
}
$host = 'http://' . $domain;
if( !$parser->isSuffixValid( $host ) )
throw new DomainInvalidException();
return $parser->parseUrl($host);
}
public function isAvailable(Url $domain)
{
$whois = new Whois($domain->host->registerableDomain);
return $whois->isAvailable();
}
但是,通过让 Whois 能够检查您的 Url
对象是否可用,并注入它,测试变得更加容易
class DomainParser
{
// Pdp\Parser should be registered as a service
public function __construct(\Pdp\Parser $parser)
{
$this->parser = $parser;
}
public function parseDomain($domain)
{
if( !$domain ) {
throw new DomainRequiredException();
}
$host = 'http://' . $domain;
if( !$parser->isSuffixValid( $host ) )
throw new DomainInvalidException();
return $parser->parseUrl($host);
}
}
class Whois
{
public function isUrlAvailable(Url $url)
{
// Whois logic
}
}
class DomainService
{
public function __construct(DomainParser $parser, Whois $whois)
{
$this->parser = $parser;
$this->whois = $whois;
}
public function isAvailable($domain)
{
$url = $this->parser->parseDomain($domain);
$this->last_checked = $url;
return $this->whois->isUrlAvailable($url);
}
}
有了这三个类,很容易对DomainService
和DomainParser
进行单元测试,Whois
可以用另一种策略来模拟和测试(假设它与第三方系统)
例如
function let(DomainParser $parser, Whois $whois)
{
$this->beConstructedWith($parser, $whois);
}
function it_shows_a_domain_is_available(
DomainParser $parser,
Whois $whois,
Url $url
) {
$parser->parseDomain('http://test.com')->willReturn($url);
$whois->isUrlAvailable($url)->willReturn(true);
$this->isAvailable('http://test.com')->shouldReturn(true);
}
function it_records_last_checked(
DomainParser $parser,
Whois $whois,
Url $url
) {
$parser->parseDomain('http://test.com')->willReturn($url);
$whois->isUrlAvailable($url)->willReturn(true);
$this->isAvailable('http://test.com');
// Note that we don't validate any properties on Url, that is the
// responsibility of the tests for DomainParser and the Url object itself
$this->getLastChecked()->shouldReturn($url);
}