Page MenuHomeDevCentral

D3202.id8169.diff
No OneTemporary

D3202.id8169.diff

diff --git a/database/README.md b/database/README.md
--- a/database/README.md
+++ b/database/README.md
@@ -35,7 +35,7 @@
As such, this extension isn't supported anymore. You can use straightforwardly
replace 'MySQL' by 'MySQLi' as engine.
-## Specialized drivers
+## Specialized drivers for tests
### Blackhole
The blackhole engine does nothing and always returns `true` as query result.
@@ -52,3 +52,48 @@
'engine' => Keruald\Database\Engines\BlackholeEngine::class,
]
```
+
+### MockDatabaseEngine
+
+The mock database is a simple implementation of the blackhole engine as mocking
+service to use when you want to return a deterministic response to known
+queries.
+
+A benefit is you don't need a running database server for your unit tests.
+
+You can pass to the `withQueries` method an array with one item per query:
+ - key: the SQL query
+ - value: an array with all rows for that query
+ -
+For example:
+
+```php
+ public function testGetFruits () : void {
+ $queries = [
+ "SELECT name, color FROM fruits" => [
+ [ "name" => "strawberry", "color" => "red" ],
+ [ "name" => "blueberry", "color" => "violet" ],
+ ],
+ ];
+
+ $db = (new MockDatabaseEngine())
+ ->withQueries($queries);
+
+ // Inject $db to a class and test it
+ }
+```
+
+To return only one row, you can use `[[…]]` to represent an array of one array:
+
+```php
+ $queries = [
+ "SELECT 1+1" => [[ "1+1" => 2 ]],
+ ];
+```
+
+The queries results are then wrapped in the MockDatabaseResult class.
+
+When the query doesn't exist, an exception is thrown.
+
+We recommend a mixed approach of the Blackhole engine when results don't matter,
+and of this class when you need some control on it.
diff --git a/database/src/Engines/BlackholeEngine.php b/database/src/Engines/BlackholeEngine.php
--- a/database/src/Engines/BlackholeEngine.php
+++ b/database/src/Engines/BlackholeEngine.php
@@ -3,6 +3,7 @@
namespace Keruald\Database\Engines;
use Keruald\Database\DatabaseEngine;
+use Keruald\Database\Result\DatabaseResult;
class BlackholeEngine extends DatabaseEngine {
@@ -10,7 +11,7 @@
return $expression;
}
- public function query (string $query) : bool {
+ public function query (string $query) : bool|DatabaseResult {
return true;
}
diff --git a/database/src/Engines/MockDatabaseEngine.php b/database/src/Engines/MockDatabaseEngine.php
new file mode 100644
--- /dev/null
+++ b/database/src/Engines/MockDatabaseEngine.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Keruald\Database\Engines;
+
+use Keruald\Database\DatabaseEngine;
+use Keruald\Database\Result\DatabaseResult;
+use Keruald\Database\Result\MockDatabaseResult;
+
+use RuntimeException;
+
+class MockDatabaseEngine extends BlackholeEngine {
+
+ private array $query_results = [];
+
+ public function withQueries(array $query_results) : self {
+ $this->query_results = $query_results;
+
+ return $this;
+ }
+
+ public function query (string $query) : DatabaseResult|bool {
+ if (!array_key_exists($query, $this->query_results)) {
+ throw new RuntimeException("Unexpected query: " . $query);
+ }
+
+ return new MockDatabaseResult($this->query_results[$query]);
+ }
+
+ public static function load (array $config) : DatabaseEngine {
+ return new self;
+ }
+}
diff --git a/database/src/Result/MockDatabaseResult.php b/database/src/Result/MockDatabaseResult.php
new file mode 100644
--- /dev/null
+++ b/database/src/Result/MockDatabaseResult.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Keruald\Database\Result;
+
+use ArrayIterator;
+use Traversable;
+
+class MockDatabaseResult extends DatabaseResult {
+
+ ///
+ /// Constructor
+ ///
+
+ public function __construct (private readonly array $results) {
+ }
+
+ ///
+ /// IteratorAggregate
+ ///
+
+ public function getIterator () : Traversable {
+ return new ArrayIterator($this->results);
+ }
+
+ ///
+ /// DatabaseResult
+ ///
+
+ public function numRows () : int {
+ return count($this->results);
+ }
+
+ public function fetchRow () : ?array {
+ static $position = 0;
+
+ if ($position < $this->numRows()) {
+ return $this->results[$position];
+ }
+
+ return null;
+ }
+}
diff --git a/database/tests/Engines/MockDatabaseEngineTest.php b/database/tests/Engines/MockDatabaseEngineTest.php
new file mode 100644
--- /dev/null
+++ b/database/tests/Engines/MockDatabaseEngineTest.php
@@ -0,0 +1,69 @@
+<?php
+
+namespace Keruald\Database\Tests\Engines;
+
+use Keruald\Database\Engines\MockDatabaseEngine;
+
+use Keruald\Database\Result\DatabaseResult;
+use PHPUnit\Framework\TestCase;
+
+class MockDatabaseEngineTest extends TestCase {
+
+ private MockDatabaseEngine $db;
+
+ const QUERY = "SELECT name, color FROM fruits";
+
+ const RESULT = [
+ [ "name" => "strawberry", "color" => "red" ],
+ [ "name" => "blueberry", "color" => "violet" ],
+ ];
+
+ protected function setUp () : void {
+ $queries = [
+ self::QUERY => self::RESULT,
+ ];
+
+ $this->db = (new MockDatabaseEngine())
+ ->withQueries($queries);
+ }
+
+ public function testNumRowsWithoutRequest () {
+ $this->assertEquals(0, $this->db->numRows());
+ }
+
+ public function testNumRowsWithRequest () {
+ $result = $this->db->query(self::QUERY);
+
+ $this->assertEquals(2, $this->db->numRows($result));
+ }
+
+ public function testQuery () {
+ $result = $this->db->query(self::QUERY);
+
+ $this->assertInstanceOf(DatabaseResult::class, $result);
+ $this->assertEquals(self::RESULT[0], $result->fetchRow());
+ }
+
+ public function testLoad () {
+ $db = MockDatabaseEngine::load([]);
+
+ $this->assertInstanceOf(MockDatabaseEngine::class, $db);
+ }
+
+ public function testFetchRow () {
+ $result = $this->db->query(self::QUERY);
+
+ $this->assertEquals(self::RESULT[0], $this->db->fetchRow($result));
+ }
+
+ public function testWithQueriesFollowsChainingPattern () {
+ $queries = [
+ self::QUERY => self::RESULT,
+ ];
+
+ $db = new MockDatabaseEngine();
+ $db = $db->withQueries($queries);
+
+ $this->assertInstanceOf(MockDatabaseEngine::class, $db);
+ }
+}
diff --git a/database/tests/Result/MockDatabaseResultTest.php b/database/tests/Result/MockDatabaseResultTest.php
new file mode 100644
--- /dev/null
+++ b/database/tests/Result/MockDatabaseResultTest.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Keruald\Database\Tests\Result;
+
+use Keruald\Database\Result\MockDatabaseResult;
+use PHPUnit\Framework\TestCase;
+
+class MockDatabaseResultTest extends TestCase {
+
+ const RESULT = [
+ [ "name" => "strawberry", "color" => "red" ],
+ [ "name" => "blueberry", "color" => "violet" ],
+ ];
+
+ private MockDatabaseResult $result;
+
+ protected function setUp () : void {
+ $this->result = new MockDatabaseResult(self::RESULT);
+ }
+
+ public function testFetchRow () {
+ $this->assertEquals(
+ [ "name" => "strawberry", "color" => "red" ],
+ $this->result->fetchRow(),
+ );
+ }
+
+ public function testNumRows () {
+ $this->assertEquals(2, $this->result->numRows());
+ }
+
+ public function testGetIterator () {
+ $i = 0;
+ foreach ($this->result as $row) {
+ $this->assertEquals(self::RESULT[$i], $row);
+ $i++;
+ }
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 25, 17:41 (19 h, 4 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2262732
Default Alt Text
D3202.id8169.diff (7 KB)

Event Timeline