Test doubles to technika w testowaniu jednostkowym, która polega na tworzeniu obiektów zastępczych dla rzeczywistych obiektów w systemie. Są one używane do izolacji jednostki testowanej i kontrolowania jej zachowania w testach.
W PHPUnit, możemy używać różnych typów test doubles, takich jak:
Dummy: Są to obiekty, które są przekazywane do testowanej jednostki, ale nigdy nie są używane.
Fake: Obiekty, które mają działającą implementację, ale są uproszczone do celów testowych.
Stubs: Obiekty, które zwracają wcześniej zdefiniowane odpowiedzi na wywołania metod.
Mocks: Obiekty, które oczekują, że określone metody zostaną wywołane z określonymi parametrami.
Spy: Obiekty, które rejestrują informacje o interakcjach i pozwalają na późniejszą weryfikację.
Atrapa (Dummy)
class OrderProcessorTest extends \PHPUnit\Framework\TestCase
{
public function testProcessOrder()
{
$dummyLogger = $this->createMock(Logger::class);
$orderProcessor = new OrderProcessor($dummyLogger);
$order = new Order();
$orderProcessor->process($order);
$this->assertTrue($order->isProcessed());
}
}
Własna implementacja
final class DummyEntityRepository implements RepositoryInterface
{
public function save(Entity $entity): void
{
}
}
Zaślepka (Stub)
Obiekt danej klasy gdzie wszystkie metody, pola zwracają puste wartości NULL. Jest to nic innego jak możliwie najprostsza implementacja danego interfejsu, która w zasadzie na nic nie reaguje ponieważ jej zachowanie jest z góry zdefiniowane. Stubem byłaby implementacja czujnika prędkości zwracająca konkretną wartość.
class UserServiceTest extends \PHPUnit\Framework\TestCase
{
public function testGetUser()
{
$userStub = $this->createMock(UserRepository::class);
$userStub->method('find')->willReturn(new User('john@example.com'));
$userService = new UserService($userStub);
$user = $userService->getUser('john@example.com');
$this->assertEquals('john@example.com', $user->getEmail());
}
}
Własna implementacja
final class StubEntityRepository implements RepositoryInterface
{
public function findOneByEmail(string $email): ?Entity
{
return new Entity($email);
}
}
Imicjacja (Mock)
Mock to tak jakby zaprogramowana imitacja, której nie tylko przekazujemy nasze oczekiwania ale również mówimy jak się ma zachować.
class UserServiceTest extends \PHPUnit\Framework\TestCase
{
public function testCreateUser()
{
$userMock = $this->createMock(UserRepository::class);
$userMock->expects($this->once())
->method('save')
->with($this->isInstanceOf(User::class));
$userService = new UserService($userMock);
$userService->createUser('john@example.com');
}
}
Szpieg (Spy)
Imitacja której celem jest nie tyle zrobienie czegoś konkretnego co sprawdzenie czy coś zostało zrobione ale bez definiowania z góry naszych oczekiwań. Spy używamy w celu zweryfikowania jakiegoś zachowania.
class UserServiceTest extends \PHPUnit\Framework\TestCase
{
public function testCreateUserWithSpy()
{
$userSpy = new UserRepositorySpy();
$userService = new UserService($userSpy);
$userService->createUser('john@example.com');
$this->assertTrue($userSpy->wasSaveCalled());
$this->assertEquals('john@example.com', $userSpy->getLastSavedUser()->getEmail());
}
}
class UserRepositorySpy extends UserRepository
{
private $saveCalled = false;
private $lastSavedUser;
public function save(User $user)
{
$this->saveCalled = true;
$this->lastSavedUser = $user;
}
public function wasSaveCalled(): bool
{
return $this->saveCalled;
}
public function getLastSavedUser(): ?User
{
return $this->lastSavedUser;
}
}
Podróbka (Fake)
Tworząc fake, tworzymy tak naprawdę imitację bardzo zbliżoną do oryginału, w dalszym stopniu jednak uproszczoną, najczęściej po to aby zasymulować konkretne zachowanie zależne od parametrów wejściowych.
class FakeDatabaseConnection
{
private $data = [];
public function insert($table, $record)
{
$this->data[$table][] = $record;
}
public function getAll($table)
{
return $this->data[$table] ?? [];
}
}
class UserServiceTest extends \PHPUnit\Framework\TestCase
{
public function testCreateUser()
{
$fakeDb = new FakeDatabaseConnection();
$userService = new UserService($fakeDb);
$userService->createUser('john@example.com');
$users = $fakeDb->getAll('users');
$this->assertCount(1, $users);
}
}
Leave a Review