【问题标题】:How can I test the type of something generated in my phpspec test?如何测试在我的 phpspec 测试中生成的东西的类型?
【发布时间】:2016-01-21 04:23:34
【问题描述】:

例如:

测试代码

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 实例。

编写测试的规则是什么,以确保我们得到包装的对象(主题)?

谢谢!

【问题讨论】:

    标签: php phpspec


    【解决方案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();
    }
    

    但是通过使 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);
        }
    }
    

    有了这三个类,很容易对DomainServiceDomainParser进行单元测试,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);
    }
    

    【讨论】:

    • Pete,非常感谢您花时间详细阐述。当前的网格是我使用的几个 packagegist 组件的函数,因此修改它们会产生连锁反应,但我可以看到好处。我想我将不得不评估重写这些项目的可测试性的商业案例。非常感谢!
    猜你喜欢
    • 2018-12-20
    • 1970-01-01
    • 1970-01-01
    • 2014-03-27
    • 1970-01-01
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    • 2013-11-07
    相关资源
    最近更新 更多