Completed
Push — master ( 7f572e...bf04a1 )
by Benedikt
02:39
created

UnitTestCase::getEntityManagerMockForQueries()   B

Complexity

Conditions 3
Paths 1

Size

Total Lines 27
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 27
c 0
b 0
f 0
cc 3
eloc 20
nc 1
nop 3
rs 8.8571
1
<?php
2
declare(strict_types=1);
3
/**
4
 * Created by PhpStorm.
5
 * User: benedikt
6
 * Date: 1/6/18
7
 * Time: 7:08 PM
8
 */
9
10
namespace Tfboe\FmLib\TestHelpers;
11
12
use Doctrine\ORM\AbstractQuery;
13
use Doctrine\ORM\EntityManager;
14
use Doctrine\ORM\QueryBuilder;
15
use PHPUnit\Framework\MockObject\MockObject;
16
use PHPUnit\Framework\TestCase;
17
18
/**
19
 * Class UnitTestCase
20
 * @package Tfboe\FmLib\TestHelpers
21
 */
22
abstract class UnitTestCase extends TestCase
23
{
24
  use ReflectionMethods;
25
  use OnlyTestLogging;
26
27
//<editor-fold desc="Protected Methods">
28
29
  /**
30
   * Creates a stub with a given set of stubbed methods, which will return the given results
31
   * @param string $class the class name
32
   * @param array $methodResults a dictionary mapping method names to results of this methods
33
   * @return MockObject the configured stub
34
   */
35
  protected function createStub(string $class, array $methodResults = []): MockObject
36
  {
37
    $entity = $this->createMock($class);
38
    foreach ($methodResults as $method => $result) {
39
      $entity->method($method)->willReturn($result);
40
    }
41
    return $entity;
42
  }
43
44
  /**
45
   * Creates an empty mock with a getId method
46
   * @param string $class the class to mock
47
   * @param string $entityId the id to assign
48
   * @param string $getterMethod the name of the getter method
49
   * @return \PHPUnit\Framework\MockObject\MockObject the mocked instance
50
   */
51
  protected function createStubWithId(string $class, $entityId = "entity-id", $getterMethod = 'getId')
52
  {
53
    return $this->createStub($class, [$getterMethod => $entityId]);
54
  }
55
56
  /**
57
   * Gets a mock for an entity manager which creates a query builder which will return a query which will return the
58
   * given result.
59
   * @param array $result the result array the query should return
60
   * @param string|null $expectedQuery the expected query if set
61
   * @param string[] $otherMockedMethods list of other methods to mock
62
   * @return MockObject the mocked entity manager
63
   */
64
  protected function getEntityManagerMockForQuery(array $result, ?string $expectedQuery = null,
65
                                                  array $otherMockedMethods = [], $amount = 1)
66
  {
67
    return $this->getEntityManagerMockForQueries(array_fill(0, $amount, $result),
68
      $expectedQuery === null ? [] : array_fill(0, $amount, $expectedQuery), $otherMockedMethods);
69
  }
70
71
  /**
72
   * Gets a mock for an entity manager which creates a query builder which will return a query which will return the
73
   * given result.
74
   * @param array $results the result arrays the queries should return
75
   * @param string[] $expectedQueries the expected queries if set
76
   * @param string[] $otherMockedMethods list of other methods to mock
77
   * @return MockObject the mocked entity manager
78
   */
79
  protected function getEntityManagerMockForQueries(array $results, array $expectedQueries = [],
80
                                                    array $otherMockedMethods = [])
81
  {
82
    $entityManager = $this->getMockForAbstractClass(EntityManager::class, [], '',
83
      false, true, true, array_merge($otherMockedMethods, ['createQueryBuilder']));
84
    assert($expectedQueries == [] || count($results) === count($expectedQueries));
85
    $entityManager->expects(static::exactly(count($results)))->method('createQueryBuilder')->willReturnCallback(
86
      function () use ($entityManager, &$results, &$expectedQueries) {
87
        $queryBuilder = $this->getMockForAbstractClass(QueryBuilder::class, [$entityManager],
88
          '', true, true, true, ['getQuery']);
89
        $query = $this->createMock(AbstractQuery::class);
90
        $query->expects(static::once())->method('getResult')->willReturn(array_shift($results));
91
        if ($expectedQueries !== []) {
92
          $queryBuilder->expects(static::once())->method('getQuery')->willReturnCallback(
93
            function () use ($queryBuilder, $query, &$expectedQueries) {
94
              /** @var QueryBuilder $queryBuilder */
95
              self::assertEquals(array_shift($expectedQueries), $queryBuilder->getDQL());
96
              return $query;
97
            });
98
        } else {
99
          $queryBuilder->expects(static::once())->method('getQuery')->willReturn($query);
100
        }
101
        return $queryBuilder;
102
      }
103
    );
104
    return $entityManager;
105
  }
106
107
  /** @noinspection PhpDocMissingThrowsInspection */
108
  /**
109
   * Gets a mock class (with full implementation). The given arguments are used for the arguments for the constructor.
110
   * If too less arguments are given mocks are created for the rest of the constructor arguments.
111
   * @param string $className the class to mock
112
   * @param array $arguments the arguments to use for the constructor
113
   * @param string[] $mockedMethods the methods to mock in the class
114
   * @return MockObject the mocked object
115
   */
116
  protected final function getMockWithMockedArguments(string $className, array $arguments = [],
0 ignored issues
show
Coding Style introduced by
As per PSR2, final should precede the visibility keyword.
Loading history...
117
                                                      array $mockedMethods = []): MockObject
118
  {
119
    /** @noinspection PhpUnhandledExceptionInspection */
120
    $reflection = new \ReflectionClass($className);
121
    $params = $reflection->getConstructor()->getParameters();
122
    $allArguments = $arguments;
123
    for ($i = count($arguments); $i < count($params); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
124
      $allArguments[] = $this->createMock($params[$i]->getClass()->name);
125
    }
126
    return $this->getMockForAbstractClass($className, $allArguments, '', true, true, true, $mockedMethods);
127
  }
128
129
  /** @noinspection PhpDocMissingThrowsInspection */
130
  /**
131
   * Gets a new instance of the given class. The given arguments are used for the arguments for the constructor.
132
   * If too less arguments are given mocks are created for the rest of the constructor arguments.
133
   * @param string $className the class for which to create an instance
134
   * @param array $arguments the arguments to use for the constructor
135
   * @return mixed an instance of the given class
136
   */
137
  protected final function getObjectWithMockedArguments($className, array $arguments = [])
0 ignored issues
show
Coding Style introduced by
As per PSR2, final should precede the visibility keyword.
Loading history...
138
  {
139
    /** @noinspection PhpUnhandledExceptionInspection */
140
    $reflection = new \ReflectionClass($className);
141
    $params = $reflection->getConstructor()->getParameters();
142
    $allArguments = $arguments;
143
    for ($i = count($arguments); $i < count($params); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
144
      $allArguments[$i] = $this->createMock($params[$i]->getClass()->name);
145
    }
146
    return new $className(...$allArguments);
147
  }
148
149
  public function tearDown()
150
  {
151
    parent::tearDown();
152
  }
153
//</editor-fold desc="Protected Methods">
154
}