Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/tarantool-php/phpunit-extras

A collection of helpers for PHPUnit to ease testing Tarantool libraries.
https://github.com/tarantool-php/phpunit-extras

phpunit phpunit-assertions phpunit-extension phpunit-extras phpunit-util tarantool

Last synced: 4 days ago
JSON representation

A collection of helpers for PHPUnit to ease testing Tarantool libraries.

Awesome Lists containing this project

README

        

# PHPUnit Extras

[![Quality Assurance](https://github.com/tarantool-php/phpunit-extras/workflows/QA/badge.svg)](https://github.com/tarantool-php/phpunit-extras/actions?query=workflow%3AQA)
[![Telegram](https://img.shields.io/badge/Telegram-join%20chat-blue.svg)](https://t.me/tarantool_php)

A collection of helpers for [PHPUnit](https://phpunit.de/) to ease testing [Tarantool](https://www.tarantool.io/en/developers/) libraries.
It is based on [rybakit/phpunit-extras](https://github.com/rybakit/phpunit-extras), please refer to this package for more documentation.

## Table of contents

* [Installation](#installation)
* [Annotations](#annotations)
* [Processors](#processors)
* [Lua](#lua)
* [Sql](#sql)
* [Requirements](#requirements)
* [LuaCondition](#luacondition)
* [TarantoolVersion](#tarantoolversion)
* [Expectations](#expectations)
* [Requests](#requests)
* [Prepared statements](#prepared-statements)
* [Mocking](#mocking)
* [Testing](#testing)
* [License](#license)

## Installation

```bash
composer require --dev tarantool/phpunit-extras
```

## Annotations

Besides the annotations provided by the package `rybakit/phpunit-extras`, the library is shipped
with annotations specific to Tarantool. The easiest way to enable them is by inheriting your test classes
from `Tarantool\PhpUnit\TestCase`:

```php
use Tarantool\Client\Client;
use Tarantool\PhpUnit\TestCase;

final class MyTest extends TestCase
{
protected function getClient() : Client
{
// TODO: Implement getClient() method.
}

// ...
}
```

Another option is to register an extension called `AnnotationExtension`:

```xml



```

By default, the extension assumes that the Tarantool server you are going to connect to is available on `127.0.0.1:3301`.
You can customize the default settings by specifying either a [DSN string](https://github.com/tarantool-php/client#dsn-string) or an [array of options](https://github.com/tarantool-php/client#array-of-options)
as extension configuration values:

```xml


tcp://127.0.0.1:3301/?socket_timeout=10

```
or
```xml




tcp://127.0.0.1:3301


10


```

On top of that, the configuration values can resolve environment variables,
which might be useful if you need to share the same settings with a Tarantool
instance file or any other script:

```xml


tcp://%env(TARANTOOL_HOST)%:%env(TARANTOOL_PORT)%

```

Once the annotations are configured, you can start using them:

### Processors

#### Lua

Allows executing Lua code before running a test.

*Example:*

```php
/**
* @lua tube:put('kick_me')
* @lua tube:bury(0)
*/
public function testKickReleasesBuriedTask() : void
{
// ...
}
```

#### Sql

Allows executing SQL statements before running a test (requires Tarantool 2.0+).

*Example:*

```php
/**
* @sql DROP TABLE IF EXISTS foobar
* @sql CREATE TABLE foobar (id INTEGER PRIMARY KEY, name VARCHAR(50))
* @sql INSERT INTO foobar VALUES (1, 'A'), (2, 'B')
*/
public function testExecuteQueryFetchesAllRows() : void
{
// ...
}
```

### Requirements

Requirements allow skipping tests based on preconditions.

#### LuaCondition

*Format:*

```
@requires luaCondition
```
where `` is an arbitrary lua expression that should be evaluated to a Boolean value.

*Example:*

```php
/**
* @requires luaCondition box.session.user() ~= 'guest'
*/
public function testChangeUserPassword() : void
{
// ...
}
```

#### TarantoolVersion

*Format:*

```
@requires Tarantool
```
where `` is a composer-like version constraint. For details on supported formats,
please see the Composer [documentation](https://getcomposer.org/doc/articles/versions.md#writing-version-constraints).

*Example:*

```php
/**
* @requires Tarantool ^2.3.2
*/
public function testPrepareCreatesPreparedStatement() : void
{
// ...
}
```

> *If you're interested in how to create and register your own annotations and requirements,
> please refer to the `rybakit/phpunit-extras` [README](https://github.com/rybakit/phpunit-extras).*

## Expectations

### Requests

To test that your code sends (or does not send) certain requests, the following methods are available:

* `TestCase::expectRequestToBeCalled(int $count) : void`
* `TestCase::expectRequestToBeCalledAtLeast(int $count) : void`
* `TestCase::expectRequestToBeCalledAtMost(int $count) : void`
* `TestCase::expectRequestToBeCalledOnce() : void`
* `TestCase::expectRequestToBeCalledAtLeastOnce() : void`
* `TestCase::expectRequestToBeCalledAtMostOnce() : void`
* `TestCase::expectRequestToBeNeverCalled() : void`
* `TestCase::expectNoRequestToBeCalled() : void`

where `` is the name of the request, for example `Call`, `Insert`, etc.
These methods are part of the `Tarantool\PhpUnit\TestCase` class, but they can also be enabled through a trait:

```php
use PHPUnit\Framework\TestCase;
use PHPUnitExtras\Expectation\Expectations as BaseExpectations;
use Tarantool\Client\Client;
use Tarantool\PhpUnit\Expectation\RequestExpectations;

final class MyTest extends TestCase
{
use BaseExpectations;
use RequestExpectations;

protected function getClient() : Client
{
// TODO: Implement getClient() method.
}

/**
* @after
*/
protected function verifyTestCaseExpectations() : void
{
$this->verifyExpectations();
}

// ...
}
```

*Example:*

```php
public function testGetSpaceIsCached() : void
{
$this->client->flushSpaces();

$this->expectSelectRequestToBeCalledOnce();
$this->client->getSpace('test_space');
$this->client->getSpace('test_space');
}
```

### Prepared statements

In order to assert prepared statement allocations, use the `Tarantool\PhpUnit\Expectation\PreparedStatementExpectations` trait,
which contains the following methods:

* `expectPreparedStatementToBe(int $count) : void`
* `expectPreparedStatementToBeAtLeast(int $count) : void`
* `expectPreparedStatementToBeAtMost(int $count) : void`
* `expectPreparedStatementToBeOnce() : void`
* `expectPreparedStatementToBeNever() : void`
* `expectPreparedStatementToBeAtLeastOnce() : void`
* `expectPreparedStatementToBeAtMostOnce() : void`

where `` is either `Allocated` or `Deallocated`.

*Example:*

```php
public function testCloseDeallocatesPreparedStatement() : void
{
$stmt = $this->client->prepare('SELECT ?');

$this->expectPreparedStatementToBeDeallocatedOnce();
$stmt->close();
}
```

To enable all the above expectation methods in one go, use the `Tarantool\PhpUnit\Expectation\Expectations` trait,
or extend the `Tarantool\PhpUnit\TestCase` class.

## Mocking

The library provides several helper classes to create test doubles for the [Tarantool Сlient](https://github.com/tarantool-php/client)
to avoid sending real requests to the Tarantool server. For the convenience of creating such objects,
add the trait `TestDoubleClient` to your test class:

```php
use PHPUnit\Framework\TestCase;
use Tarantool\PhpUnit\Client\TestDoubleClient;

final class MyTest extends TestCase
{
use TestDoubleClient;

// ...
}
```

> *If your test cases extend the `Tarantool\PhpUnit\TestCase` class, this step is not needed
> because the trait is already included in that class.*

A dummy client object can be created as follows:

```php
public function testFoo() : void
{
$dummyClient = $this->createDummyClient();

// ...
}
```

To simulate specific scenarios, such as establishing a connection to a server
or returning specific responses in a specific order from the server, use the facilities
of the `TestDoubleClientBuilder` class. For example, to simulate the `PING` request:

```php
use Tarantool\Client\Request\PingRequest;
use Tarantool\PhpUnit\TestCase;

final class MyTest extends TestCase
{
public function testFoo() : void
{
$mockClient = $this->getTestDoubleClientBuilder()
->shouldSend(new PingRequest())
->build();

// ...
}

// ...
}
```

Another example, sending two `EVALUATE` requests and returning a different response for each:

```php
use Tarantool\Client\RequestTypes;
use Tarantool\PhpUnit\Client\TestDoubleFactory;
use Tarantool\PhpUnit\TestCase;

final class MyTest extends TestCase
{
public function testFoo() : void
{
$mockClient = $this->getTestDoubleClientBuilder()
->shouldSend(
RequestTypes::EVALUATE,
RequestTypes::EVALUATE
)->willReceive(
TestDoubleFactory::createResponseFromData([2]),
TestDoubleFactory::createResponseFromData([3])
)->build();

// ...
}

// ...
}
```
The above example can be simplified to:

```php
$mockClient = $this->getTestDoubleClientBuilder()
->shouldHandle(
RequestTypes::EVALUATE,
TestDoubleFactory::createResponseFromData([2]),
TestDoubleFactory::createResponseFromData([3])
)->build();
```

Besides, the builder allows setting custom `Connection` and `Packer` instances:

```php
$stubClient = $this->getMockClientBuilder()
->willUseConnection($myConnection)
->willUsePacker($myPacker)
->build();
```

## Testing

Before running tests, the development dependencies must be installed:

```bash
composer install
```

Then, to run all the tests:

```bash
vendor/bin/phpunit
vendor/bin/phpunit -c phpunit-extension.xml
```

## License

The library is released under the MIT License. See the bundled [LICENSE](LICENSE) file for details.