Laravel Query Factory, is library for you to easily mock your query builder without sending query from real database.
The library is to use for developers who really follow the Automating Testing, The unit test is the most low level where you need tto test your whole system.
In laravel is one of the problem, where most of the tutorials and even in document of laravel, the testing is mostly focusing in integration, api and acceptance.
Example of this test are:
<?php
// Model
use Illuminate\Database\Eloquent\Model;
class Person extends Model {
}
// Repository
use Illuminate\Support\Collection;
class PersonRepository
{
public function findPerson(int $id): ?Person
{
return Person::find(1);
}
}
// Test
class PersonRepositoryTest extends TestCase
{
public function testFindPerson()
{
factory(Person::class)->create(['id' => 1]);
$person = $this->app->make(PersonRepository::class)->findPerson(1);
$this->assertInstanceOf(Person::class, $person);
$this->assertSame(1, $person->id);
}
}
Fromm our example, this is an Integration test, not a unit test. Why? We will answer that why using the list below: * Unit test a single unit in your system, this are your method and functions. * If possible any function going out to your class must be in mock form.
- this is possible if you doing dependency injection
- this is possible if you are doing SOLID
From this list and from the example, our test was calling a database, if you call find from your model this will immediately call a query using your connection.
Oops!!!, why not use sqlite, since sqlite is just a file base and can be use without other database? The answer is dont use sqlite for test to just satisfy your unit test, Why? * Using sqlite, is still consider outside of your class and can still be consider as 3rd party service. * Not all sql query can handler my sqlite, each database driver have different syntax, especially if you are using NoSQL.
|Class|Description|
|-----|-----------|
|LaravelQueryFactory\Facades\QueryFactoryFacade|A class for facade use by laravel and lumen|
|LaravelQueryFactory\QueryFactory|The main service that will generate query builder|
|LaravelQueryFactory\QueryFactoryProvider|Provider that will register the LaravelQueryFactory\QueryFactory
as query-factory
|
|Trait|Description|
|-----|-----------|
|LaravelQueryFactory\Models\Traits\QueryFactoryTrait|Trait that can use by the model to replace the default newBaseQueryBuilder
|
|LaravelQueryFactory\Traits\MockQueryFactory|A trait use for testing, to mock connection and pdo|
composer require cydrickn/laravel-query-factory
The configuration can be found to config/app.php
.
To register your provider, add it to the array:
'providers' => [
// Other Service Providers
LaravelQueryFactory\QueryFactoryProvider::class,
];
Model will just use the LaravelQueryFactory\Models\Traits\QueryFactoryTrait
this will use the facade or you can also
set the QueryFactory using by calling setQueryFactory
Adding QueryFactoryTrait
to your model, this will replace the current generation of Query Builder
using QueryFactoryFacade
so that you can mock it.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use LaravelQueryFactory\Models\Traits\QueryFactoryTrait;
class Person extends Model
{
use QueryFactoryTrait;
protected $fillable = ['name', 'gender'];
}
Creating repository or service is just you normal service.
It's your choice if you will inject LaravelQueryFactory\QueryFactory
,
but in this example we will not since we use the default QueryFactory from our facades.
Person Repository
<?php
namespace App\Repository;
use App\Models\Person;
use Illuminate\Support\Collection;
class PersonRepository
{
public function findById(): ?Person
{
return Person::find(1);
}
public function findByGender(string $gender): Collection
{
return Person::where('gender', '=', $gender)->get();
}
}
For our unit test you need to use LaravelQueryFactory\Traits\MockQueryFactory
.
This trait will mock the connection class use by laravel so that it will not connect to any type of database.
for function mockConnection
it is accepting:
- mysql
- postgres
- sqlite
- sqlserver
Why we need to specify this drivers? so that you can get the generated query for test, since every driver has different queries on how they convert your query builder. But I suggest that you use the driver use by your system, so that you can really check your expectation sql.
<?php
namespace App\Tests\Unit;
use LaravelQueryFactory\Traits\MockQueryFactory;
use LaravelQueryFactory\Facades\QueryFactoryFacade;
class PersonRepositoryTest extends TestCase
{
use MockQueryFactory;
/
* Test by just using mock connection and QueryFacades
* and you can assert the generated sql.
*/
public function testFindWithGeneratedSql()
{
$connection = $this->mockConnection('mysql');
$queryBuilder = Person::newQueryBuilder();
$queryBuilder->connection = $connection;
QueryFactoryFacade::shouldReceive('createQueryBuilder')->andReturn($queryBuilder);
$repository = new PersonRepository();
$repository->findById(1);
$this->assertSame('select * from `people` where `people`.`id` = ? limit 1', $queryBuilder->toSql());
$this->assertSame([1], $queryBuilder->getBindings());
}
/
* Test by mocking connection with result and QueryFacades
*/
public function testFindWithResult()
{
$connection = $this->mockConnection('mysql');
// Mock result from connection
$connection->shouldReceive('select')->once()->andReturn([['id' => 1]]);
$queryBuilder = Person::newQueryBuilder();
$queryBuilder->connection = $connection;
QueryFactoryFacade::shouldReceive('createQueryBuilder')->andReturn($queryBuilder);
$repository = new PersonRepository();
$person = $repository->findById(1);
$this->assertInstanceOf(Person::class, $person);
}
/
* Test by mocking query builder
*/
public function testFindByGenderWithMockingQueryBuilder()
{
$connection = $this->mockConnection('mysql');
// Mocking Query Builder
$queryBuilder = Mockery::mock(QueryBuilder::class);
$queryBuilder->shouldReceive('getConnection')->andReturn($connection);
$queryBuilder->shouldReceive('from')->with('people')->andReturnSelf();
$queryBuilder->shouldReceive('where')->once()->with('gender', '=', 'male')->andReturnSelf();
$queryBuilder->shouldReceive('get')->once()->with(['*'])->andReturnSelf();
$queryBuilder->shouldReceive('all')
->once()
->withNoArgs()
->andReturn([['id' => 1, 'gender' => 'male']]);
QueryFactoryFacade::shouldReceive('createQueryBuilder')->andReturn($queryBuilder);
$repository = new PersonRepository();
$persons = $repository->findByGender('male');
$this->assertSame(1, $persons->first()->id);
}
}
Using this library (Laravel Query Factory) you can now mock your query builders. By mocking the connection will mock the connection so that it will not connect to database.
Classes of Cydrick Nonog | > | PHP Query Builder for Laravel | > | Download .zip .tar.gz | > | Support forum | > | Blog | > | Latest changes |
|
|
Groups | Applications | Files |
Groups |
PHP 5 | Classes using PHP 5 specific features | View top rated classes |
Databases | Database management, accessing and searching | View top rated classes |
Testing | Tools to help verifying that software works as expected | View top rated classes |
Applications that use this package |
If you know an application of this package, send a message to the author to add a link here.
Files |
File | Role | Description | ||
---|---|---|---|---|
.github (1 directory) | ||||
src (2 files, 3 directories) | ||||
tests (2 directories) | ||||
composer.json | Data | Auxiliary data | ||
LICENSE | Lic. | License text | ||
phpunit.xml | Data | Auxiliary data | ||
README.md | Doc. | Read me |
Files | / | src |
File | Role | Description | ||
---|---|---|---|---|
Facades (1 file) | ||||
Models (1 directory) | ||||
Traits (1 file) | ||||
QueryFactory.php | Class | Class source | ||
QueryFactoryProvider.php | Class | Class source |
Files | / | tests | / | Integration |
File | Role | Description |
---|---|---|
Person.php | Class | Class source |
PersonRepository.php | Class | Class source |
PersonRepositoryTest.php | Class | Class source |
PersonTest.php | Class | Class source |
TestCase.php | Class | Class source |
Files | / | tests | / | Unit |
File | Role | Description | ||
---|---|---|---|---|
Facades (1 file) | ||||
Models (1 directory) | ||||
Traits (1 file) | ||||
QueryFactoryProviderTest.php | Class | Class source | ||
QueryFactoryTest.php | Class | Class source | ||
TestCase.php | Class | Class source |
Files | / | tests | / | Unit | / | Models | / | Traits |
File | Role | Description |
---|---|---|
QueryFactoryTraitTest.php | Class | Class source |
Download all files: laravel-query-factor.tar.gz laravel-query-factor.zip NOTICE: if you are using a download manager program like 'GetRight', please Login before trying to download this archive.
|