具有不止一种方法的嘲弄学说/存储库

Posted

技术标签:

【中文标题】具有不止一种方法的嘲弄学说/存储库【英文标题】:Mockery Doctrine / Repository with more than one method 【发布时间】:2016-03-07 05:59:28 【问题描述】:

我正在使用嘲弄来测试一种方法,该方法使用不同的存储库进行大量的学说存储库调用。 这是我设置所有存储库模拟的方法:

public function testService()

    $mockDoctrine = $this->getMockDoctrine();
    $mockDoctrine->shouldReceive('getRepository')->once()
        ->andReturn($this->getRepositoryAMock());

    $mockDoctrine->shouldReceive('getRepository')->once()
        ->andReturn($this->getRepositoryBMock());

    $mockDoctrine->shouldReceive('getRepository')->once()
        ->andReturn($this->getRepositoryCMock());

    //here is where i hit my test
    $products = $this->service->fire(1, 1);

    $this->assertInstanceOf('Illuminate\Support\Collection', $products);
    foreach ($products as $v) 
        $this->assertInstanceOf('Illuminate\Support\Collection', $v);
    

这是我嘲笑教义的方法:

public function getMockDoctrine()

    $mockDoctrine = \App::make('Doctrine');
    $mockDoctrine->shouldReceive('persist')
        ->andReturn(true);
    $mockDoctrine->shouldReceive('flush')
        ->andReturn(true);

    return $mockDoctrine;

这些是我的存储库模拟

public function getRepositoryAMock()

    $repository = \Mockery::mock('MyARepository');
    $repository->shouldReceive('findBy')
        ->with(['paramA' => 1, 'paramB' => 1])
        ->andReturn($this->getMockA());

    return $repository;


public function getRepositoryBMock()

    $repository = \Mockery::mock('MyBRepository');
    $repository->shouldReceive('findById')
        ->with(1)
        ->andReturn($this->getMockA());

    return $repository;


public function getRepositoryCMock()

    $repository = \Mockery::mock('MyCRepository');
    $repository->shouldReceive('findOneBy')
        ->with(['paramA' => 1, 'paramB' => 1])
        ->andReturn($this->getMockA());

    return $repository;

这实际上是我设置模拟返回的地方

public function getMockA()

    $obj = new MyClass();
    $reflection = new \ReflectionClass($obj);
    $id = $reflection->getProperty('id');
    $id->setAccessible(true);
    $id->setValue($obj, 1);
    $obj
        ->setLogin('foo')
        ->setPassword('bar')
        ->setCode(1);

    return $obj;

然后我收到这样的错误:

1) MyClassTest::testService BadMethodCallException:此模拟对象上不存在方法 Mockery_2_ClassBRepository::findOneBy()

假设我有 3 个方法在 testService() 方法中调用了存储库,那么 mockery 没有找到的方法在第三个中,但 mockery 认为它在第二个中,所以显然他不会找到,因为在第二个中,不存在第三个中的“findOneBy()”学说方法。

我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

你应该能够使用嘲弄的 with()。 例如:

$mockDoctrine
    ->shouldReceive('getRepository')
    ->with('MyAReposiotry')->once()
    ->andReturn($this->getRepositoryAMock());

对于每个存储库都是如此(具有不同的价值)。

但我宁愿在该服务中注入存储库,而不是从服务内部的实体管理器中获取它。这对测试来说更好。看看this blog post。

【讨论】:

“with”出现了其他错误:Mockery\Exception\NoMatchingExpectationException:没有为 Mockery_1_ 找到匹配的处理程序。该方法是意外的,或者它的参数与该方法的预期参数列表不匹配 你确定你在 with() 中输入了正确的值吗?您应该使用与该实体相同的值来使该实体投入使用。 是的,是一样的,我应该在“getRepositoryAMock”方法中改变一些东西吗? 实际上没有(如果 MyARepository 是具有正确命名空间的真实类)。但问题是我正在使用实体名称而不是存储库名称(->getRepository('Bundle:SomeEntity') 而不是 ->getRepository('SomeRepository'))获取我的存储库。这就是为什么问你是否确定你是否正在获得这样的存储库。也许您可以粘贴服务本身。 哦,是的,它成功了!我也在使用实体来获取存储库,我在代码中更改了它,它现在可以工作了!非常感谢伊万先生。 =)【参考方案2】:

感谢伊万先生,

现在我的方法奏效了。

在我的真实课堂中,我正在使用实体类获取存储库, 喜欢:

 Doctrine::getRepository('MyEntityClassA')
        ->findBy(['paramA' => 1, 'paramB' => 1]);

所以我改变了我的测试方法以使用“with”传递实体类:

public function testService()

    $mockDoctrine = $this->getMockDoctrine();
    $mockDoctrine->shouldReceive('getRepository')
        ->with('MyEntityClassA')->once()
        ->andReturn($this->getRepositoryAMock());

    $mockDoctrine->shouldReceive('getRepository')->once()
        ->with('MyEntityClassB')->once()
        ->andReturn($this->getRepositoryBMock());

    $mockDoctrine->shouldReceive('getRepository')->once()
        ->with('MyEntityClassC')->once()
        ->andReturn($this->getRepositoryCMock());

    //here is where i hit my test
    $products = $this->service->fire(1, 1);

    $this->assertInstanceOf('Illuminate\Support\Collection', $products);
    foreach ($products as $v) 
        $this->assertInstanceOf('Illuminate\Support\Collection', $v);
    

【讨论】:

以上是关于具有不止一种方法的嘲弄学说/存储库的主要内容,如果未能解决你的问题,请参考以下文章

错误:在 null 上调用成员函数 create(),单元测试(嘲弄)

嘲弄“应该接收”但方法不存在

Symfony - 在服务中注入学说存储库

嘲弄:测试具有不同返回值的链式方法调用(此处:Symfony ProcessBuilder)

需要一种内置方式来为现有存储库添加死锁弹性到 Dapper 而不更改它们

oauth2-server-php-docs 存储 学说2