Architecture PhpSpec正确测试服务层

Architecture PhpSpec正确测试服务层,architecture,tdd,repository-pattern,behat,phpspec,Architecture,Tdd,Repository Pattern,Behat,Phpspec,应用程序有多个服务,其中一些功能与多个服务重叠。由于我一次只能测试一项服务 背景: 群组服务可以创建诸如“红色汽车”、“蓝色汽车”之类的群组。 汽车服务可以将汽车分配给各个组 团体服务: function createGroup($name); function assignCarToGroup($car, $group); 汽车服务: function createGroup($name); function assignCarToGroup($car, $group); 问题: 当我

应用程序有多个服务,其中一些功能与多个服务重叠。由于我一次只能测试一项服务

背景: 群组服务可以创建诸如“红色汽车”、“蓝色汽车”之类的群组。 汽车服务可以将汽车分配给各个组

团体服务:

function createGroup($name);
function assignCarToGroup($car, $group);
汽车服务:

function createGroup($name);
function assignCarToGroup($car, $group);
问题: 当我在PhpSpec中描述汽车服务时,我想确保它能够检查汽车是否已成功分配给一个组

要做到这一点,在将汽车分配给该小组之前,该小组必须存在

问题: 我需要在运行文件之前创建组。这就是我面临的问题

如果我依靠前面的示例(GroupServiceSpec)来创建组,我会使测试变得非常脆弱

如何测试车辆是否已在车辆服务范围内成功分配

GroupService.php

<?php

namespace App;

class GroupService
{
    private $group_repository;

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

    public function CreateGroupServiceCall($name)
    {
        return $this->group_repository->createGroup($name);
    }
}
<?php

namespace App;

class CarService
{
    private $car_repository;

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

    public function AssignCarToGroupServiceCall($car, $group_name)
    {
        return $this->car_repository->assignCarToGroup($car, $group_name);
    }
}

您的汽车服务规格应该如下所示:

class CarServiceSpec extends ObjectBehavior
{

  function let(CarRepository $carRepository)
  {
    $this->beConstructedWith($carRepository);
  }

  function it_is_initializable()
  {
    $this->shouldHaveType(CarService::class);
  }

  function it_can_assign_car_to_group(CarRepository $carRepository)
  {
    $car = 'Car I';
    $group_name = 'Group1';

    $carRepository->assignCarToGroup($car, $group_name)->shouldBeCalled()->willReturn(true);

    $this->AssignCarToGroupServiceCall($car, $group_name)->shouldReturn(true);
  }
}

我认为您可能对您的用例使用了错误的工具。Phpspec是用于单元测试的,所以如果您指定了汽车服务,那么您可能必须使用存根组服务。如果您想测试两者之间的集成,请使用Behat.Hello@gvf,非常感谢。实际上,我也在使用Behat。但是,我还想确保这个特定的函数在单元测试级别上工作。我认为嘲笑它是不够的,因为需要真正的条目。你会让它不进行单元测试吗?或者如果你想在单元测试级别对它进行测试,你的解决方案是什么?单元测试单独测试一个类,你想测试两个类之间的交互,所以我要做的是将测试移到Behat。如果您发布这两个类的完整代码,我可能会为您提供进一步的帮助。@gvf下面是我编写的代码的快速实现:我还将它添加到问题中。好的,首先,不要调用类“*Service.php`:-”),它太模糊,如果您有多个服务,会发生什么?在你的情况下,在CarServiceSpec,你只能说明行为:你只能说明调用<代码> CARYRealPosioS>分配CudioGue,没有别的。谢谢你GVF在这部分之后,我应该认为它是“验证”的,即使我知道结果不在那里吗?我可以说,“我的重点是部件,是否调用了正确的方法?”非常感谢,这就是您可以做的。如果您想确保它在DB中持久化,那么请进行Behat测试。非常感谢!整个事情也有behat在上面,我只是想确定一下。非常感谢。
<?php

namespace spec\App;

use App\GroupRepository;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class GroupRepositorySpec extends ObjectBehavior
{

    function letGo()
    {
        # Clean up and remove all DB files
        array_map('unlink', glob(__DIR__ . "/../../*.db"));
    }

    function it_is_initializable()
    {
        $this->shouldHaveType(GroupRepository::class);
    }

    function it_can_create_group()
    {
        $status = $this->createGroup('test');
        $status->shouldBe(true);
    }
}
<?php

namespace spec\App;

use App\CarRepository;
use App\CarService;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class CarServiceSpec extends ObjectBehavior
{

    function let()
    {
        $car_repository = new CarRepository();
        $this->beConstructedWith($car_repository);
    }

    function it_is_initializable()
    {
        $this->shouldHaveType(CarService::class);
    }

    function it_can_assign_car_to_group()
    {
        $car = 'Car I';
        $group_name = 'Group1';

        $this->AssignCarToGroupServiceCall($car, $group_name)->shouldBe(true);
    }
}
<?php

namespace spec\App;

use app\CarRepository;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

class CarRepositorySpec extends ObjectBehavior
{
    function it_is_initializable()
    {
        $this->shouldHaveType(CarRepository::class);
    }

    function it_can_assign_car_to_group()
    {
        # how can I test this part, as the group is not existing now.
        # If I'm not to create the group, how can I test if this code works at all?
        # Do I have a design error?

        $car = 'Car1';
        $group_name = 'Company';

        $this->assignCarToGroup($car, $group_name)->shouldBe(true);
    }
}
class CarServiceSpec extends ObjectBehavior
{

  function let(CarRepository $carRepository)
  {
    $this->beConstructedWith($carRepository);
  }

  function it_is_initializable()
  {
    $this->shouldHaveType(CarService::class);
  }

  function it_can_assign_car_to_group(CarRepository $carRepository)
  {
    $car = 'Car I';
    $group_name = 'Group1';

    $carRepository->assignCarToGroup($car, $group_name)->shouldBeCalled()->willReturn(true);

    $this->AssignCarToGroupServiceCall($car, $group_name)->shouldReturn(true);
  }
}