magetest/magento-phpspec-extension

此包已废弃,不再维护。未建议替代包。

Magento PHPSpec 扩展

5.0.0 2017-12-10 14:48 UTC

README

Build Status Scrutinizer Code Quality Latest Stable Version Packagist Downloads License

安装

使用 Composer 安装

首先,将 MageSpec 添加到 composer.json 中依赖列表中,并确保注册了一些自动加载路径

{
    "require-dev": {
        "magetest/magento-phpspec-extension": "^5.0"
    },
    "config": {
        "bin-dir": "bin"
    },
    "autoload": {
        "psr-0": {
            "": [
                "public/app",
                "public/app/code/local",
                "public/app/code/community",
                "public/app/code/core",
                "public/lib"
            ]
        }
    }
}

然后只需使用 composer 进行安装即可

$ composer install

您可以在其 官方网页 上了解更多关于 Composer 的信息。

SpecBDD 和 TDD

SpecBDD 和 TDD 之间没有真正的区别。使用 xSpec 工具代替常规 xUnit 工具进行 TDD 的价值在于语言。工具的概念和特性将使您专注于“正确”的事情。与行为和设计相比,关注验证和结构当然是一个合理的观点。我们偶然发现,从长远来看,后者更有价值。这也是 TDD 早期用户的目的。

SpecBDD 和 StoryBDD

虽然 StoryBDD 工具(如 Behat)用于理解并阐明领域 - 指定功能叙事、其需求以及我们所说的含义,但 SpecBDD 我们只关注如何实现:实现。您指定类如何实现这些功能。

一个好的 StoryBDD 工具将让业务人员使用领域语言,并通过关注真正重要的事情来驱动开发。

一旦您知道为什么要添加一个功能以及它将是什么,就几乎可以开始编写代码了。但还不是时候!在没有验证代码是否满足规格的情况下添加代码,意味着您将不得不回去重做,以确保它与规格匹配。您发现遗漏了需求或添加了错误的时间越晚,修复它就越困难、越昂贵。Kent Beck 也补充说,在编写代码之前描述代码是一种恐惧管理技巧。您不必编写所有代码,只需编写您接下来要工作的下一个东西的规格即可。这个可执行的规格将指导您需要编写什么代码。一旦您这样做,那么您拥有的就是一个重构的机会。因为如果您的代码行为发生变化,规格将变成红色。所以您编写规格是为了可以重构,或者允许代码的设计以可持续的方式出现。SpecBDD 工具旨在指导您在这个过程中,或者至少不要挡路。

假设 StoryBDD 和 SpecBDD 一起使用是一种非常有效的方法来达到高度以客户为中心的软件。

基本用法

MageSpec 已作为 PhpSpec 扩展开发,这意味着它依赖于它,并且我们需要告诉 PhpSpec 为我们加载扩展。为了做到这一点,我们必须在项目根目录中创建一个名为 phpspec.yml 的文件,并将以下内容添加到其中

extensions:
    MageTest\PhpSpec\MagentoExtension\Extension: ~

然而这还不够。由于 Magento 使用非标准惯例存储控制器、模型、助手等,MageSpec 实现了一个自定义的 PhpSpec 定位器服务。这种定位器必须根据我们的项目配置进行适当配置,这意味着我们还需要添加一些 'mage_locator' 配置,如下所示

extensions:
    MageTest\PhpSpec\MagentoExtension\Extension:
        mage_locator:
            src_path: public/app/code
            spec_path: spec/public/app/code

目前 mage_locator 支持五个选项

  • namespace (默认 ''): 我们源代码的基本命名空间
  • spec_prefix (默认 'spec'): 用于基于源代码命名空间命名规格的命名空间前缀
  • src_path (默认 'src'): 源代码的相对路径
  • spec_path (默认 '.'): 规格的相对路径
  • code_pool (默认 'local'): 指定创建扩展文件的 Magento 代码池。选项是 'local' 和 'community'

描述一个模型

假设我们正在构建一个模块,该模块会告诉我们某个产品是否有现有的评论。我们将先从简单的事情做起,并设计出一个能够涵盖所有必要功能的方案。尽管我拥有客户的所有规格(我们完成了所有 Behat 功能文件),但我知道当我坐下来编写类时,我将会发现新的需要。

我最想添加的最简单的事情是什么?它应该告诉我一个产品是否有评论。

所以让我们这样做。嗯,不是无聊的部分。让 MageSpec 来处理无聊的事情。我们只需要告诉 MageSpec 我们将工作在 Review 模块的产品类上。所以运行以下命令

$ bin/phpspec describe:model 'magespec_reviews/product'

应该给出以下输出

Specification for MageSpec_Reviews_Model_Product created in [...]/spec/public/app/code/local/MageSpec/Reviews/Model/ProductSpec.php

好的。我们刚才做了什么?MageSpec 已经根据标准的 Magento 惯例为我们创建了规格。您可以导航到规格文件夹并查看那里的规格

<?php

namespace spec;

use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class MageSpec_Reviews_Model_ProductSpec extends ObjectBehavior
{
    function it_is_initializable()
    {
        $this->shouldHaveType('MageSpec_Reviews_Model_Product');
    }
}

太棒了!MageSpec 为我创建了规格。

但首先,让我们看看这里有什么。我们的规格扩展了特殊的 ObjectBehavior 类。这个类很特殊,因为它让您能够调用您正在描述的类的所有方法,并将操作的结果与您的期望进行匹配。

示例

对象行为由示例组成。示例被包含在公共方法中,以 it_ 或 its_ 开头。phpspec 会搜索您的规范以运行这些方法。为什么示例名称要以下划线开头?只是为了使其比一些LongCamelCasingLikeThat更容易阅读。

匹配器

匹配器与 xUnit 中的断言非常相似,除了匹配器专注于说明对象应该如何表现,而不是验证其如何工作。它更好地表达了关注行为,并更适合测试驱动周期。目前 phpspec 中有 5 个匹配器,但几乎每个匹配器都有一个别名,使您的示例读起来更加流畅

  • Identity (return, be, equal, beEqualTo) - 它类似于检查 ===
  • Comparison (beLike) - 它类似于检查 ==
  • Throw (throw -> during) - 用于测试异常
  • Type (beAnInstanceOf, returnAnInstanceOf, haveType) - 检查对象类型
  • ObjectState (have**) - 检查对象是否是**方法返回值

您如何使用这些?您只需在它们前面加上 shouldshouldNot,具体取决于您的期望,然后在感兴趣的主题上调用它们。

现在我们准备继续前进。让我们更新第一个示例以表达我的下一个意图

<?php

namespace spec;

use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class MageSpec_Reviews_Model_ProductSpec extends ObjectBehavior
{
    // ...

    function it_tells_if_a_product_has_reviews()
    {
        $this->load('SKU');
        $this->hasReviews()->shouldReturn(true);
    }

    // ...
}

现在怎么办?我们运行规格。您可能不会相信,但 MageSpec 会理解我们正在描述一个不存在的类,并建议创建它!

$ bin/phpspec

MageSpec_Reviews_Model_Product
  10  ! it is initializable
      class MageSpec_Reviews_Model_Product does not exists.

-----------------------100%----------------------- 1

1 example (1 broken)
11ms

Do you want me to create `MageSpec_Reviews_Model_Product` for you? [Y/n]
Model MageSpec_Reviews_Model_Product created in [...]/public/app/code/local/MageSpec/Reviews/Model/Product.php.

MageSpec 现在已经将空类放入了目录中。

<?php

class MageSpec_Reviews_Model_Product extends Mage_Core_Model_Abstract
{

}

您再次运行规格,然后... 好的,您猜对了

$ bin/phpspec
MageSpec_Reviews_Model_Product
  15  ! it tells if a product has reviews
      method MageSpec_Reviews_Model_Product::load() not found.

-----------------------97%----------------------- 2

2 examples (1 passed, 1 broken)
12ms


Do you want me to create `MageSpec_Reviews_Model_Product::load()` for you? [Y/n]
Method MageSpec_Reviews_Model_Product::load() has been created.

然后...

$ bin/phpspec
MageSpec_Reviews_Model_Product
  15  ! it tells if a product has reviews
      method MageSpec_Reviews_Model_Product::hasReviews() not found.

-----------------------97%----------------------- 2

@ examples (1 passed, 1 broken)
12ms


Do you want me to create `MageSpec_Reviews_Model_Product::hasReviews()` for you? [Y/n]
Method MageSpec_Reviews_Model_Product::hasReviews() has been created

我们刚才做的事情是快速通过琥珀状态进入红色状态。如果您检查您的类,您现在应该看到类似这样的内容

<?php

class MageSpec_Reviews_Model_Product extends Mage_Core_Model_Abstract
{
    public function load($argument1)
    {
        // TODO: write logic here
    }

    public function hasReviews()
    {
        // TODO: write logic here
    }
}

我们消除了由于不存在类和方法导致的致命错误和丑陋的消息,并直接进入了真正的失败规范。

$ bin/phpspec
MageSpec_Reviews_Model_Product
  15  ✘ it tells if a product has reviews
      expected true, but got null.

-----------------------97%----------------------- 2

2 examples (1 passed, 1 failed)
11ms

根据TDD规则,我们现在有充分的权限来编写代码。红色表示“是时候添加代码”了;红色太棒了!现在我们添加足够的代码,快速地将规范变为绿色。我们会有时间使其正确,但首先让它变为绿色。

<?php

class MageSpec_Reviews_Model_Product
{

    public function load($argument1)
    {
        // TODO: write logic here
    }

    public function hasReviews()
    {
        return true;
    }
}

看看吧!

$ bin/phpspec
----------------------100%----------------------- 2

2 example (2 passed)
11ms

如果你对PHP中的规范感兴趣,最好查看官方PhpSpec页面,或者,如果你对整个TDD/SpecBDD循环更感兴趣,已经有大量的资源了。这里为你提供一些供参考:

  • 《Rspec Book:使用RSpec、Cucumber和朋友的开发》由David Chelimsky、Dave Astels、Zach Dennis、Aslak Hellesøy、Bryan Helmkamp、Dan North所著
  • 《测试驱动开发:示例》由Kent Beck所著

额外支持的命令

截至今天,MageSpec目前允许你描述不同的Magento类。以下是一个简要列表。

描述一个块

$ bin/phpspec describe:block 'vendorname_modulename/blockname'

描述一个辅助函数

$ bin/phpspec describe:helper 'vendorname_modulename/helpername'

描述一个控制器

$ bin/phpspec describe:controller 'vendorname_modulename/helpername'

问题提交

在您提交一个新问题之前,请确保您已经阅读了问题提交指南

贡献

请参阅贡献文档

许可和作者

作者:https://github.com/MageTest/MageSpec/contributors

版权(C)2012-2013

在此特此授予任何获得此软件及其相关文档副本(以下简称“软件”)的人免费使用该软件的权利,不受限制地处理该软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本,并允许向提供软件的人提供使用该软件的权利,前提是遵守以下条件:

上述版权声明和本许可声明应包含在所有副本或实质部分中。

软件按“原样”提供,不提供任何形式的保证,无论是明示的、暗示的,还是关于适销性、特定用途适用性或非侵权性的保证。在任何情况下,作者或版权所有者不对任何索赔、损害或其他责任(无论因合同、侵权或其他原因引起)承担责任,即使已经被告知该软件或其使用可能引起此类损害。