phpspec - 方法返回对象而不是字符串

时间:2014-07-31 00:51:40

标签: php symfony testing phpspec

我在phpspec中仍然很新鲜,但通常我会在遇到困难时找到解决方案,但这个很难。

我尝试了很多不同的方法,但我还没有找到解决方案。我正在使用Symfony2。

我有一个我想测试的课程:

class MyClass
{

    public function getDataForChildren(MyObject $object)
    {
        foreach ($object->getChildren() as $child) {
            $query = \json_decode($child->getJsonQuery(), true);
            $data = $this->someFetcher->getData($query);
            $child->setData($data);
        }
        return $object;
    }

}

在这里看看我的spec类:

class MyClassSpec
{

    function let(SomeFetcher $someFetcher)
    {
        $this->beConstructedWith($someFetcher);
    }

    function it_is_initializable()
    {
        $this->shouldHaveType('MyClass');
    }

    function it_should_get_data_for_children_and_return_object(
        MyClass $object,
        MyClass $child, // it means that MyClass has a self-reference to MyClass
        $someFetcher
    )
    {
        $query = '{"id":1}';

        $returnCollection = new ArrayCollection(array($child));

        $object->getChildren()->shouldBeCalled()->willReturn($returnCollection);

        $child->getJsonQuery()->shouldBeCalled()->willReturn($query);

        $someFetcher->getData($query)->shouldBeCalled();

        $this->getDataForChildren($object);
    }

}

在运行phpspec之后,我收到了这个错误:

warning: json_decode() expects parameter 1 to be string, object given in

我不知道如何解决这个问题。如果有人有线索,请帮忙。

1 个答案:

答案 0 :(得分:5)

这是PhpSpec的常见绊脚石,声明:

   MyClass $child

表示$ child的Collaborator对象将使用MyClass的相同接口进行设置。 当在SUT(您正在测试的类)中调用child-> getJsonQuery()时,它将返回 MethodProphecy ,而不是您希望它返回的字符串。

你想说的是你的ArrayCollection将包含 not $ child本身(它是一个Collaborator对象),但是包含协作者的真实对象。你这样做:

$returnCollection = new ArrayCollection(array($child->getWrappedObject()));
  

此外,你不应该使用(即多余)   shouldBeCalled()和willReturn()在同一个Collaborator上,一个或者一个   其他就足够了。如果您已指定合作者将使用的内容   返回,显然它将在SUT中被称为。   shouldBeCalled()应该用在"断言"部分考试在   为了确认Collaborator是按预期调用的   论证,或在正确的时间。

你的最终SUT和规格看起来应该是这样的:

   class MyClass
   {

        /**
         * @var SomeFetcher
         */
        private $someFetcher;

        public function getDataForChildren(MyObject $object)
        {
            foreach ($object->getChildren() as $child) {
                $query = \json_decode($child->getJsonQuery(), true);
                $data = $this->someFetcher->getData($query);
                $child->setData($data);
            }
            return $object;
        }

        public function getJsonQuery()
        {
        }

        public function setData()
        {
        }

        public function __construct(SomeFetcher $someFetcher)
        {
            $this->someFetcher = $someFetcher;
        }
    }

class MyClassSpec extends ObjectBehavior
{

    function let(SomeFetcher $someFetcher)
    {
        $this->beConstructedWith($someFetcher);
    }

    function it_should_get_data_for_children_and_return_object(
        MyObject $object,
        MyClass $child, // it means that MyClass has a self-reference to MyClass
        SomeFetcher $someFetcher
    )
    {
        $query = '{"id":1}';

        $returnCollection = new ArrayCollection(array($child->getWrappedObject()));

        $object->getChildren()->willReturn($returnCollection);

        $child->getJsonQuery()->willReturn($query);
        $child->setData(Argument::any())->shouldBeCalled();

        $someFetcher->getData(array('id' => 1))->shouldBeCalled();

        $this->getDataForChildren($object);
    }

}

此外,该行

$query = \json_decode($child->getJsonQuery(), true);

将在$ query中生成一个关联数组,即数组(' id' => 1)(这是json_encode规定的第二个' true'参数),因此你& #39; d期望用后者调用$ someFetcher-> getData(),因此:

$someFetcher->getData(array('id' => 1))->shouldBeCalled();