【问题标题】:How to write repository test without executing query on db如何在不对数据库执行查询的情况下编写存储库测试
【发布时间】:2019-05-08 06:32:31
【问题描述】:

我已经花费了我的大部分时间试图为我的存储库功能创建一个适当的 Phpunit 测试,但仍然没有成功,所以这就是我向你们寻求帮助的原因

我正在尝试编写一个测试,它正在测试我的存储库功能,而不连接到数据库

我有这个存储库功能(Symfony 4)

class RequestRepository extends EntityRepository
{
   public function getCompletedRequestByName($name)
        {
            $requestsStatuses = $this->createQueryBuilder('r')
                ->join('r.domains', 'd', Join::WITH, 'r.id = d.request')
                ->where('r.name = :name')
                ->andWhere('r.status = :completed')
                ->setParameter('name', $name)
                ->setParameter('completed', 'COMPLETED')
                ->getQuery()
                ->getOneOrNullResult();
            return $requestsStatuses;
        }
}

这是我的测试

public function testGetCompletedRequestByName()
{
    $entityM =
        $this->getMockBuilder(EntityManagerInterface::class)
            ->disableOriginalConstructor()
            ->getMockForAbstractClass();

    $classMetaData =
        $this->getMockBuilder(ClassMetadata::class)
            ->disableOriginalConstructor()
            ->getMockForAbstractClass();

    $repo = new RequestRepository($entityM, $classMetaData);
    var_dump($repo->getCompletedRequestByName('antrax.com'));
    die();
}

我得到的错误是

1) App\Repository\RequestRepositoryTest::testGetCompletedRequestByName
Error: Call to a member function select() on null

有人可以帮助我,如何编写测试,测试我的存储库功能,无需连接到数据库并执行任何查询。如果您需要任何其他信息,请告诉我,我会提供!谢谢!

【问题讨论】:

  • 您基本上需要调整模拟实体管理器以返回一个模拟查询构建器,然后检查加入、选择等调用。这是一个真正的痛苦,而且可能很脆弱,因为任何调整都会导致测试失败。另外,它并没有真正检查您的查询本身是否会返回预期的数据。这就是为什么有些人只是创建一个测试数据库(可能使用 sqlite)并实际执行查询的原因之一。
  • 你好,你能发一个示例代码吗?谢谢

标签: doctrine-orm doctrine phpunit symfony4


【解决方案1】:

我找到了适合我的情况的解决方案。如果有任何机构需要,这就是我的测试的样子

public function testGetCompletedRequestByName()
{

    $queryBuilder = $this->getMockBuilder(QueryBuilder::class)->disableOriginalConstructor()
        ->setMethods(['setParameter', 'getQuery', 'getOneOrNullResult', 'join', 'andWhere', 'where'])->getMock();

    $queryBuilder->method('getQuery')->willReturnSelf();

    $queryBuilder->method('setParameter')->willReturnCallback(function ($field, $value) use ($queryBuilder){
        if ($field == 'name') {
            $this->assertSame('antrax.com', $value);
        } elseif ($field == 'completed') {
            $this->assertSame('COMPLETED', $value);
        }
        return $queryBuilder;
    });

    $queryBuilder->method('join')->willReturnCallback(function ($field, $alias, $operator, $cond) use ($queryBuilder){

        $this->assertSame('r.domains', $field);
        $this->assertSame('d', $alias);
        $this->assertSame(Join::WITH, $operator);
        $this->assertSame('r.id = d.request', $cond);

        return $queryBuilder;
    });

    $queryBuilder->method('where')->willReturnCallback(function ($cond) use ($queryBuilder){

        $this->assertSame('r.name = :name', $cond);
        return $queryBuilder;
    });

    $queryBuilder->method('andWhere')->willReturnCallback(function ($cond) use ($queryBuilder){

        $this->assertSame('r.status = :completed', $cond);
        return $queryBuilder;
    });

    $repositoryMock =
        $this->getMockBuilder(RequestRepository::class)->disableOriginalConstructor()
            ->setMethods(['createQueryBuilder'])->getMock();

    $repositoryMock->method('createQueryBuilder')->willReturnCallback(function ($alias) use ($queryBuilder){
        $this->assertSame('r', $alias);
        return $queryBuilder;
    });

    $repositoryMock->getCompletedRequestByName('antrax.com');
}

【讨论】:

  • 恭喜您解决了这个问题。没有看到你在哪里测试 QueryBuilder::getQuery 调用,当然你真的应该为它模拟一个 Query 并验证 getOneOrNullResults 是否被调用。虽然完全偏离主题,但有趣的是,您的返回状态有复数形式,但最多只能返回一个状态。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-13
  • 1970-01-01
  • 2017-09-08
  • 2020-04-29
  • 2011-04-15
相关资源
最近更新 更多