Skip to content

Commit

Permalink
Adds unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
butschster committed May 30, 2022
1 parent f0da5e5 commit 0a418c2
Show file tree
Hide file tree
Showing 11 changed files with 335 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/CommandBus.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function dispatch(CommandInterface $command): mixed
/** @var HandledStamp $stamp */
$stamp = $envelope->last(HandledStamp::class);

return $stamp->getResult();
return $stamp?->getResult();
} catch (NoHandlerForMessageException $e) {
throw new CommandNotRegisteredException($command, $e);
} catch (HandlerFailedException $e) {
Expand Down
6 changes: 3 additions & 3 deletions src/QueryBus.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public function ask(QueryInterface $query): mixed
/** @var HandledStamp $stamp */
$stamp = $envelope->last(HandledStamp::class);

return $stamp->getResult();
} catch (NoHandlerForMessageException) {
throw new QueryNotRegisteredException($query);
return $stamp?->getResult();
} catch (NoHandlerForMessageException $e) {
throw new QueryNotRegisteredException($query, $e);
} catch (HandlerFailedException $e) {
$this->throwException($e);
}
Expand Down
17 changes: 17 additions & 0 deletions tests/app/Command/StoreUser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

declare(strict_types=1);

namespace Spiral\Cqrs\Tests\App\Command;

use Spiral\Cqrs\CommandInterface;

final class StoreUser implements CommandInterface
{
public function __construct(
public string $uuid,
public string $username,
public string $password
) {
}
}
10 changes: 10 additions & 0 deletions tests/app/EntityManagerInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Spiral\Cqrs\Tests\App;

interface EntityManagerInterface
{
public function store(array $data): void;
}
27 changes: 27 additions & 0 deletions tests/app/Handler/StoreUserHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace Spiral\Cqrs\Tests\App\Handler;

use Spiral\Cqrs\Tests\App\Command\StoreUser;
use Spiral\Cqrs\Tests\App\EntityManagerInterface;

final class StoreUserHandler
{
public function __construct(
private EntityManagerInterface $entityManager
) {

}

#[\Spiral\Cqrs\Attribute\CommandHandler]
public function __invoke(StoreUser $command)
{
$this->entityManager->store([
'uuid' => $command->uuid,
'username' => $command->username,
'password' => $command->password
]);
}
}
22 changes: 22 additions & 0 deletions tests/app/Handler/UsersQueries.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Spiral\Cqrs\Tests\App\Handler;

use Spiral\Cqrs\Tests\App\Query\FindUserById;
use Spiral\Cqrs\Tests\App\UserRepositoryInterface;

final class UsersQueries
{
public function __construct(
private UserRepositoryInterface $users
) {
}

#[\Spiral\Cqrs\Attribute\QueryHandler]
public function findById(FindUserById $query): array
{
return $this->users->findByPK($query->id);
}
}
15 changes: 15 additions & 0 deletions tests/app/Query/FindUserById.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Spiral\Cqrs\Tests\App\Query;

use Spiral\Cqrs\QueryInterface;

final class FindUserById implements QueryInterface
{
public function __construct(
public int $id
) {
}
}
10 changes: 10 additions & 0 deletions tests/app/UserRepositoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Spiral\Cqrs\Tests\App;

interface UserRepositoryInterface
{
public function findByPk(int $pk): array;
}
89 changes: 89 additions & 0 deletions tests/src/CommandBusTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

declare(strict_types=1);

namespace Spiral\Cqrs\Tests;

use Mockery as m;
use Spiral\Cqrs\CommandBus;
use Spiral\Cqrs\CommandInterface;
use Spiral\Cqrs\Exception\CommandNotRegisteredException;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\HandlerFailedException;
use Symfony\Component\Messenger\Exception\NoHandlerForMessageException;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Stamp\HandledStamp;

final class CommandBusTest extends TestCase
{
private CommandBus $bus;
private m\LegacyMockInterface|MessageBusInterface|m\MockInterface $messageBus;
private m\LegacyMockInterface|m\MockInterface|CommandInterface $command;

protected function setUp(): void
{
parent::setUp();

$this->bus = new CommandBus(
$this->messageBus = m::mock(MessageBusInterface::class)
);
$this->command = m::mock(CommandInterface::class);
}

public function testDispatch(): void
{
$this->messageBus->shouldReceive('dispatch')
->once()
->with($this->command)
->andReturn(
new Envelope(new \stdClass(), [
new HandledStamp('foo', 'bar'),
])
);

$this->assertSame('foo', $this->bus->dispatch($this->command));
}

public function testDispatchWithoutStamp(): void
{
$this->messageBus->shouldReceive('dispatch')
->once()
->with($this->command)
->andReturn(new Envelope(new \stdClass(), []));

$this->assertNull($this->bus->dispatch($this->command));
}

public function testNoHandlerForMessageException(): void
{
$this->expectException(CommandNotRegisteredException::class);
$this->expectErrorMessage(
\sprintf('The command <%s> hasn\'t a command handler associated', $this->command::class)
);

$this->messageBus->shouldReceive('dispatch')
->once()
->with($this->command)
->andThrow(new NoHandlerForMessageException());

$this->bus->dispatch($this->command);
}

public function testHandlerFailedException(): void
{
$this->expectException(\Exception::class);
$this->expectErrorMessage('Something went wrong.');

$envelope = new Envelope(new \stdClass(), []);

$exception = new \Exception('Something went wrong.');
$this->messageBus->shouldReceive('dispatch')
->once()
->with($this->command)
->andThrow(new HandlerFailedException($envelope, [
$exception
]));

$this->bus->dispatch($this->command);
}
}
51 changes: 51 additions & 0 deletions tests/src/HandlersLocatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace Spiral\Cqrs\Tests;

use Spiral\Cqrs\Tests\App\Command\StoreUser;
use Spiral\Cqrs\Tests\App\EntityManagerInterface;
use Spiral\Cqrs\Tests\App\Query\FindUserById;
use Spiral\Cqrs\Tests\App\UserRepositoryInterface;

final class HandlersLocatorTest extends TestCase
{
public function testHandleCommand(): void
{
$em = $this->mockContainer(EntityManagerInterface::class);

$em->shouldReceive('store')->once()->with([
'uuid' => 'uuid-string',
'username' => 'john_smith',
'password' => 'secret',
]);

$this->getContainer()
->get(\Spiral\Cqrs\CommandBusInterface::class)->dispatch(
new StoreUser(
'uuid-string',
'john_smith',
'secret'
)
);
}

public function testHandleQuery(): void
{
$em = $this->mockContainer(UserRepositoryInterface::class);

$em->shouldReceive('findByPk')->once()->with(123)->andReturn(
$user = [
'uuid' => 'uuid-string',
'username' => 'john_smith',
'password' => 'secret',
]
);

$this->assertSame(
$user,
$this->getContainer()->get(\Spiral\Cqrs\QueryBusInterface::class)->ask(new FindUserById(123))
);
}
}
90 changes: 90 additions & 0 deletions tests/src/QueryBusTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

namespace Spiral\Cqrs\Tests;

use Mockery as m;
use Spiral\Cqrs\Exception\CommandNotRegisteredException;
use Spiral\Cqrs\Exception\QueryNotRegisteredException;
use Spiral\Cqrs\QueryBus;
use Spiral\Cqrs\QueryInterface;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Exception\HandlerFailedException;
use Symfony\Component\Messenger\Exception\NoHandlerForMessageException;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Stamp\HandledStamp;

final class QueryBusTest extends TestCase
{
private QueryBus $bus;
private m\LegacyMockInterface|MessageBusInterface|m\MockInterface $messageBus;
private m\LegacyMockInterface|m\MockInterface|QueryInterface $query;

protected function setUp(): void
{
parent::setUp();

$this->bus = new QueryBus(
$this->messageBus = m::mock(MessageBusInterface::class)
);
$this->query = m::mock(QueryInterface::class);
}

public function testAsk(): void
{
$this->messageBus->shouldReceive('dispatch')
->once()
->with($this->query)
->andReturn(
new Envelope(new \stdClass(), [
new HandledStamp('foo', 'bar'),
])
);

$this->assertSame('foo', $this->bus->ask($this->query));
}

public function testDispatchWithoutStamp(): void
{
$this->messageBus->shouldReceive('dispatch')
->once()
->with($this->query)
->andReturn(new Envelope(new \stdClass(), []));

$this->assertNull($this->bus->ask($this->query));
}

public function testNoHandlerForMessageException(): void
{
$this->expectException(QueryNotRegisteredException::class);
$this->expectErrorMessage(
\sprintf('The query <%s> hasn\'t a query handler associated', $this->query::class)
);

$this->messageBus->shouldReceive('dispatch')
->once()
->with($this->query)
->andThrow(new NoHandlerForMessageException());

$this->bus->ask($this->query);
}

public function testHandlerFailedException(): void
{
$this->expectException(\Exception::class);
$this->expectErrorMessage('Something went wrong.');

$envelope = new Envelope(new \stdClass(), []);

$exception = new \Exception('Something went wrong.');
$this->messageBus->shouldReceive('dispatch')
->once()
->with($this->query)
->andThrow(new HandlerFailedException($envelope, [
$exception
]));

$this->bus->ask($this->query);
}
}

0 comments on commit 0a418c2

Please sign in to comment.