【问题标题】:How to create class variables in a PHPSpec spec file that can be used for all examples in the spec如何在 PHPSpec 规范文件中创建可用于规范中所有示例的类变量
【发布时间】:2018-02-27 11:25:24
【问题描述】:

我有一个包含许多示例的 PHPSpec 类。我希望能够在规范类中创建可供类中任何示例函数使用的类变量。

下面是一个非常简化的版本:

class ThingImTestingSpec extends ObjectBehavior
{
    private $common_variables_array = [
        'property_1' => value_1,
        'property_2' => 'Value 2'
    ];

    function it_finds_a_common_property()
    {
        $object_1 = new ConstructedObject;

        $this->find_the_common_property($object_1)->shouldReturn($this->common_variables_array['property_1']);
    }
}

问题在于 PHPSpec 如何(巧妙地)实例化和引用被测类。在规范方法中对$this 的引用实际上是指测试对象,而不是规范类本身。

但这意味着尝试使用$this->class_variable 引用类变量会引用测试对象上的类变量,而不是规范。

所以。如何在规范类本身的范围内创建一组变量,这些变量可以在运行时由示例访问?

我尝试过的事情:

  • 将类变量放在构造函数中 - 仍然无法通过示例访问
  • 使用beConstructedWith - 需要更改被测类,以便对其进行测试。不是一个干净的解决方案。
  • 当我要引用的常见对象是数据库记录时,我可以使用 Eloquent 通过 id(或其他属性)引用它们,每次都从 Model 构建一个集合或类对象。 这可行,但很耗时,因为我需要在每个规范函数中构建集合或对象。我想在规范类被实例化时构建一次这些集合和对象,并在整个类中引用它们。

我还没有尝试过的事情:

  • 在规范类和被测类的范围之外创建第三个对象来容纳通用对象和变量,这些对象和变量可以在运行时由规范类方法(示例)访问。此解决方案可能有效,但如果有更清洁的解决方案,它会在规范中添加一个我希望避免的层。

注意:我不是在寻找以上述方式进行测试的“替代方案”,除非它们仍然适合更广泛的需求。这个例子非常精简。在实践中,我正在扩展LaravelObjectBehavior (https://github.com/BenConstable/phpspec-laravel),使用规范的构造函数通过 Factory 和 Faker 类 (https://github.com/thephpleague/factory-muffin) 在测试数据库中创建记录,并在测试后销毁它们 (League\FactoryMuffin\Facade: :deleteSaved() 在规范的析构函数中)。我希望能够在任意数量的规范函数中引用由模型表示的对象(并由 FactoryMuffin 创建),因此我不必在每个规范函数中重新创建这些对象和集合。是的,我知道这超出了“规范”测试的范围,但是当应用程序被绑定到模型时,与数据层交互的对象仍然是“规范的”,这是可以争论的。

我目前正在使用 phpspec 2.2.1 和 Laravel 4.2

【问题讨论】:

    标签: laravel factory phpspec


    【解决方案1】:

    我们目前在我们的软件中使用 PHPSpec v3。请使用let 方法声明常见的东西。快速示例:

    <?php
    
    class ExampleSpec extends \PhpSpec\ObjectBehavior
    {
        private $example; // private property in the spec itself
    
        function let()
        {
            $this->example = (object) ['test1' => 'test1']; // setting property of the spec
            parent::let();
        }
    
        function it_works()
        {
            var_dump($this->example); // will dump: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
        }
    
        function it_works_here_as_well()
        {
            var_dump($this->example); // will dump same thing as above: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
            $this->example = (object) ['test2' => 'test2']; // but setting here will be visible only for this example
        }
    
        function it_is_an_another_example()
        {
            var_dump($this->example); // will dump same thing first two examples: object(stdClass)#1 (1) { ["test1"] => string(5) "test1" }
        }
    }
    

    【讨论】:

    • 确认此方法也适用于 PHPSpec 版本 2.2.1,使用不带函数参数的 let()
    • 嗯,是的,参数不是必需的:)我会更新代码
    【解决方案2】:

    找到了答案。将类变量显式声明为static,并且可以通过spec类中的方法访问:

    class ThingImTestingSpec extends ObjectBehavior
    {
        private static $common_variables_array = [
            'property_1' => value_1,
            'property_2' => 'Value 2'
        ];
    
        function it_finds_a_common_property()
        {
            $object_1 = new ConstructedObject;
    
            $this->find_the_common_property($object_1)->shouldReturn($this::$common_variables_array['property_1']);
        }
    }
    

    这适用于数组以及表示使用 Eloquent 构建的数据库记录的对象,例如

    class LaravelAppClassImTestingSpec extends LaravelObjectBehavior
    {
        private static $Order_1;
    
        function __construct()
        {
            $Order_1 = \Order::find(123);
        }
    
        function it_tests_a_thing()
        {
            //(the method has access to the static class variable via
            //$this::$Order_1
        }
    }
    

    【讨论】:

    • 重要! 确保在规范和被测类中为类变量命名不同。例如$spec_variable_1 与 $variable_1 以区分它们。这很重要,例如,当使用变量来保存相对文件路径时,这对于规范和被测类来说是不同的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-01
    • 2016-02-24
    • 2014-05-02
    • 2018-06-16
    • 2018-01-09
    • 2020-11-05
    • 1970-01-01
    相关资源
    最近更新 更多