2016-01-21 69 views
1

例如:如何测试我的phpspec测试中生成的东西的类型?

测试代码

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构件我想测试其类型例。它似乎没有返回一个包装对象,它返回实际的Pdp \ Uri \ Url实例。

写作测试中的规则是什么,以确保我们获得包装物体(主体)?

谢谢!

回答

1

您在测试此逻辑时遇到的困难是PhpSpec试图推动您采用不同的设计。您的测试正在验证并依赖6/7其他对象的行为/结构,使其成为更多集成测试而不是单元测试(在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类的构造/实例化和分裂验证/从Whois解析逻辑检查你的东西是更容易测试了一下(但不太方便的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(); 
} 

但通过使域名注册能够检查,如果你的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); 
    } 
} 

有了这三个类,很容易单元测试DomainServiceDomainParserWhois可以嘲笑和使用另一种策略(假设它与第三方系统通信)进行测试

例如

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); 
} 
+0

皮特,非常感谢您花时间详细说明了这些细节。当前的网格是我使用的几个packagist组件的功能,修改它们会产生连锁反应,但我可以看到它的好处。我想我必须评估重写这些项目的可测试性的商业案例。非常感谢! – Saeven