2016-01-21 64 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