Stub
Permasalahan Unit Test
Kadang membuat unit test untuk sebuah class bukanlah hal yang mudah, apalagi
jika ternyata class tersebut tergantung dengan object lain.
Apalagi jika ternyata object yang dibutuhkan ternyata tergantung dengan
object lain lagi.
Hal seperti ini akan sangat menyulitkan saat membuat unit test.
Sebagai contoh kita akan coba membuat studi kasus sederhana membuat class
yang kompleks.
Product
<?php
namespace BikinBalik\Test;
class Product
{
private string $id, $name, $description;
private int $price, $quantity;
/**
* @return string
*/
public function getId(): string
{
return $this->id;
}
/**
* @param string $id
*/
public function setId(string $id): void
{
$this->id = $id;
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @param string $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @return string
*/
public function getDescription(): string
{
return $this->description;
}
/**
* @param string $description
*/
public function setDescription(string $description): void
{
$this->description = $description;
}
/**
* @return int
*/
public function getPrice(): int
{
return $this->price;
}
/**
* @param int $price
*/
public function setPrice(int $price): void
{
$this->price = $price;
}
/**
* @return int
*/
public function getQuantity(): int
{
return $this->quantity;
}
/**
* @param int $quantity
*/
public function setQuantity(int $quantity): void
{
$this->quantity = $quantity;
}
}
Product Repository
<?php
namespace BikinBalik\Test;
interface ProductRepository
{
function save(Product $product): Product;
function delete(Product $product): Void;
function findById(string $id): ?Product;
function findAll(): array;
}
Product Service
<?php
namespace BikinBalik\Test;
class ProductService
{
public function __construct(private ProductRepository $repository)
{
}
public function register(Product $product): Product
{
if ($this->repository->findById($product->getId()) != null)
{
throw new \Exception("Product is already exists");
}
return $this->repository->save($product);
}
}
Stub
Saat akan membuat test untuk sebuah class, dan ternyata class tersebut butuh
dependency object lain, maka kita bisa membuat object pengganti yang bisa
kita konfigurasi agar sesuai dengan keinginan kita.
Teknik ini dinamakan stubbing, dan object pengganti yang kita buat disebut
stub.
PHPUnit mendukung pembuatan object stub secara mudah hanya dengan
menggunakan function createStub(className) yang terdapat di class TestCase.
method createStub() secara otomatis akan membuat object class atau interface
yang kita inginkan dengan default implementation.
Membuat Stub
Konfigurasi Stub
Secara default, semua function di stub akan mengembalikan null jika nullable return type, atau default value jika tipe data primitive, atau stub lain jika tipe data class.
Biasanya kita akan melakukan konfigurasi stub terlebih dahulu sebelum kita menggunakan stub.
Dengan begitu, kita bisa memprediksi tingkah laku stub tersebut sesuai dengan konfigurasi yang kita buat.
Melakukan konfigurasi stub sederhananya hanya memberi tahu stub, jika sebuah function di eksekusi, kita ingin mengembalikan data apa.
Invocation Stubber
Stub memiliki function yang bernama method(name), dimana dia akan mengembalikan InvocationStubber.
Dengan InvocationStubber, kita bisa mengatur hasil kembalian dari function yang dipanggil di stub.
https://github.com/sebastianbergmann/phpunit/blob/master/src/Framework/MockObject/Builder/InvocationStubber.php .
Secara Defaut Mengmbalikan Nilai NULL
Kode Konfigurasi Stub
Kode Konfigurasi Stub dengan Map
Kode Konfigurasi Stub dengan Callback
Integrasi Dengan Stub
Sekarang kita sudah tahu cara menggunakan stub.
Jika kita akan membuat uni test untuk sebuah class, dan ternyata class tersebut membutuhkan object lain, maka disarankan untuk menggunakan stub.
Hal ini agar tingkah laku stub bisa kita konfigurasi, sehingga perubahan yang terjadi di class asli stub nya tidak akan mempengaruhi unit test kita.