Memulai dengan Phpspec
Indonesian (Bahasa Indonesia) translation by Arief Syahrir (you can also view the original English article)
Dalam tutorial ini pendek, belum komprehensif, kita akan melihat behavior driven development (BDD) dengan phpspec. Sebagian besar, itu akan menjadi pengantar tool phpspec, tetapi ketika kami pergi, kami akan menyentuh pada konsep-konsep BDD yang berbeda. BDD adalah topik panas hari ini dan phpspec telah mendapatkan banyak perhatian dalam komunitas PHP baru saja.
SpecBDD & Phpspec
BDD adalah semua tentang menggambarkan perilaku perangkat lunak, untuk mendapatkan desain yang tepat. Hal ini sering dikaitkan dengan TDD, tapi sedangkan TDD berfokus pada pengujian aplikasi Anda, BDD lebih tentang menggambarkan perilaku. Dengan menggunakan pendekatan BDD akan memaksa Anda untuk terus-menerus mempertimbangkan persyaratan aktual dan perilaku yang diinginkan dari perangkat lunak yang Anda sedang bangun.
Dua tool BDD telah mendapatkan banyak perhatian dalam komunitas PHP baru-baru ini, Behat dan phpspec. Behat membantu Anda menggambarkan perilaku eksternal aplikasi Anda, menggunakan bahasa Gherkin dapat dibaca. phpspec, di sisi lain, membantu Anda menggambarkan perilaku internal aplikasi Anda, dengan menulis kecil "spesifikasi" di bahasa PHP - maka SpecBDD. Spesifikasi ini menguji bahwa kode Anda memiliki perilaku yang diinginkan.
Apa yang akan kita lakukan
Dalam tutorial ini, kita akan membahas segala sesuatu yang berkaitan dengan phpspec. Perjalanan kami, kami akan membangun fundament todo daftar aplikasi, langkah demi langkah, dengan menggunakan pendekatan SpecBDD. Ketika kita pergi, kita akan memiliki phpspec memimpin jalan!
Catatan: Ini adalah artikel menengah tentang PHP. Saya menganggap Anda memiliki pemahaman yang baik tentang PHP berorientasi objek.
Instalasi
Untuk tutorial ini, saya menganggap Anda memiliki hal-nal berikut dan berjalan:
- PHP yang bekerja (min. 5.3)
- Composer
Instalasi phpspec melalui composer adalah cara termudah. Semua yang harus Anda lakukan adalah menjalankan perintah berikut dalam terminal:
1 |
$ composer require phpspec/phpspec
|
2 |
Please provide a version constraint for the phpspec/phpspec requirement: 2.0.*@dev |
Ini akan membuat composer.json
file untuk Anda dan menginstal phpspec di vendor/
Direktori.
Untuk memastikan bahwa semuanya bekerja, menjalankan phpspec
dan melihat bahwa Anda mendapatkan output yang berikut:
1 |
$ vendor/bin/phpspec run
|
2 |
|
3 |
0 specs |
4 |
0 examples |
5 |
0ms |
Konfigurasi
Sebelum kita mulai, kita perlu melakukan sedikit konfigurasi. ketika phpspec berjalan, akan mencarifile YAML bernama phpspec.yml
. Karena kami akan menempatkan kode kita dalam sebuah namespace, kita perlu memastikan bahwa phpspec tahu tentang hal ini. Juga, sementara kita berada di itu, mari kita pastikan bahwa spesifikasi kami terlihat bagus dan cantik saat kami menjalankan mereka.
Pergi ke depan dan membuat file dengan isi sebagai berikut:
1 |
formatter.name: pretty |
2 |
suites: |
3 |
todo_suite: |
4 |
namespace: Petersuhm\Todo |
Ada banyak opsi konfigurasi lain tersedia, yang Anda dapat baca dalam dokumentasi.
Hal lain yang perlu kita lakukan, adalah untuk memberitahu composer bagaimana autoload kode kita. phpspec akan menggunakan autoloader composer, sehingga hal ini diperlukan untuk spesifikasi kami untuk dijalankan.
Menambahkan unsur autoload ke file composer.json
bahwa Composer dibuat untuk Anda:
1 |
{
|
2 |
"require": { |
3 |
"phpspec/phpspec": "2.0.*@dev" |
4 |
},
|
5 |
"autoload": { |
6 |
"psr-0": { |
7 |
"Petersuhm\\Todo": "src" |
8 |
}
|
9 |
}
|
10 |
}
|
Menjalankan composer dump-autoload
akan memperbarui autoloader setelah perubahan ini.
Spec pertama kami
Sekarang kita siap untuk menulis spec pertama kami. Kita akan mulai dengan menggambarkan class yang disebut TaskCollection
. Kita akan memiliki phpspec menghasilkan spesifikasi class bagi kita dengan menggunakan perintah describe
(atau alternatif desc
versi pendek).
1 |
$ vendor/bin/phpspec describe "Petersuhm\Todo\TaskCollection" |
2 |
$ vendor/bin/phpspec run
|
3 |
Do you want me to create `Petersuhm\Todo\TaskCollection` for you? y |
Jadi apa yang terjadi di sini? Pertama, kami meminta phpspec untuk menciptakan spesifikasi untuk TaskCollection
. Kedua, kami menjalankan spec kami suite dan kemudian phpspec otomatis ditawarkan untuk menciptakan class TaskCollection
yang sebenarnya untuk kami. Keren, bukan?
Pergi ke depan dan menjalankan suite lagi, dan Anda akan melihat bahwa kita sudah memiliki satu contoh spec kami (kita akan melihat dalam sekejap apa contoh):
1 |
$ vendor/bin/phpspec run
|
2 |
|
3 |
Petersuhm\Todo\TaskCollection |
4 |
|
5 |
10 ✔ is initializable |
6 |
|
7 |
|
8 |
1 specs |
9 |
1 examples (1 passed) |
10 |
7ms |
Dari output ini, kita dapat melihat bahwa TaskCollection
initializable. Tentang apakah ini? Lihatlah spec file phpspec yang dihasilkan, dan itu harus jelas:
1 |
<?php
|
2 |
|
3 |
namespace spec\Petersuhm\Todo; |
4 |
|
5 |
use PhpSpec\ObjectBehavior; |
6 |
use Prophecy\Argument; |
7 |
|
8 |
class TaskCollectionSpec extends ObjectBehavior |
9 |
{
|
10 |
function it_is_initializable() |
11 |
{
|
12 |
$this->shouldHaveType('Petersuhm\Todo\TaskCollection'); |
13 |
}
|
14 |
}
|
Ungkapan 'initializable' berasal dari fungsi bernama it_is_initializable()
phpspec yang telah ditambahkan ke class yang disebut TaskCollectionSpec
. Fungsi ini adalah apa yang kita sebut sebagai contoh. Dalam contoh khusus ini, kami memiliki apa yang kita sebut sebagai matcher yang disebut shouldHaveType()
yang memeriksa jenis TaskCollection
kami. Jika Anda mengubah parameter yang dimasukan ke fungsi ini ke sesuatu yang lain dan menjalankan spec lagi, Anda akan melihat bahwa itu akan gagal. Sebelum benar-benar memahami hal ini, saya pikir kita perlu menyelidiki dalam variabel $this
merujuk kepada spec kami.
Apa itu $this
?
Tentu saja, $this
merujuk ke instance class TaskCollectionSpec
, karena ini adalah hanya biasa kode PHP. Tetapi dengan phpspec, Anda harus memperlakukan $this
berbeda dari apa yang Anda biasanya lakukan, karena di belakang layar, itu sebenarnya merujuk ke objek di bawah tes, yang sebenarnya adalah class TaskCollection
. Perilaku ini mewarisi dari kelas ObjectBehavior
, yang membuat yakin bahwa fungsi panggilan proxy spec'ed class. Ini berarti bahwa SomeClassSpec
akan proxy metode panggilan ke instance SomeClass
. phpspec akan membungkus panggilan metode ini untuk menjalankan kembali nilai-nilai mereka terhadap matchers seperti yang Anda hanya lihat.
Anda tidak memerlukan pemahaman yang mendalam ini untuk menggunakan phpspec, hanya ingat bahwa sejauh Anda tahu, $this
sebenarnya merujuk ke objek di bawah tes.
Membangun Task Collection
Sejauh ini, kita belum melakukan apa-apa sendiri. Tapi phpspec telah membuat kelas TaskCollection
kosong untuk kita gunakan. Sekarang adalah waktu untuk mengisi beberapa kode dan membuat class ini berguna. Kami akan menambahkan dua metode: add()
metode, untuk menambahkan tugas, dan count()
metode, untuk menghitung jumlah tugas dalam koleksi.
Menambahkan tugas
Sebelum kita menulis kode apapun nyata, kita harus menulis contoh spec kami. Dalam contoh kita, kami ingin mencoba untuk menambahkan tugas ke koleksi, dan kemudian setelah itu membuat yakin bahwa tugas bahkan ditambahkan. Untuk melakukan ini, kita perlu instance class (sejauh tidak ada) Task
. Jika kita menambahkan ketergantungan ini sebagai parameter ke fungsi spec kami, phpspec akan secara otomatis memberikan kita contoh yang dapat kita gunakan. Sebenarnya, instance bukan instance asli, tapi apa phpspec mengacu sebagai Collaborator
. Objek ini akan bertindak sebagai objek yang sesungguhnya, tetapi phpspec memungkinkan kita untuk melakukan lebih banyak barang mewah dengan ini, yang kita akan melihat segera. Meskipun Task
class tidak ada lagi, untuk saat ini, hanya berpura-pura itu. Membuka TaskCollectionSpec
dan menambahkan pernyataan use
untuk Task
class dan kemudian menambahkan contoh it_adds_a_task_to_the_collection():
1 |
use Petersuhm\Todo\Task; |
2 |
|
3 |
...
|
4 |
|
5 |
function it_adds_a_task_to_the_collection(Task $task) |
6 |
{
|
7 |
$this->add($task); |
8 |
$this->tasks[0]->shouldBe($task); |
9 |
}
|
Dalam contoh kita, kita menulis kode "kami berharap bisa memiliki". Kita memanggil metode add()
dan kemudian mencoba untuk memberikan $task
. Kemudian kami memeriksa bahwa task bahkan ditambahkan ke variabel instance $tasks.
Matcher shouldBe()
adalah identitas matcher mirip dengan PHP ===
komparator. Anda dapat menggunakan baik shouldBe()
, shouldBeEqualTo()
, shouldEqual()
atau shouldReturn()
- mereka semua melakukan hal yang sama.
Phpspec berjalan akan menghasilkan beberapa kesalahan, karena kita tidak memiliki class bernama Task
.
Mari kita memiliki phpspec memperbaikinya bagi kita:
1 |
$ vendor/bin/phpspec describe "Petersuhm\Todo\Task" |
2 |
$ vendor/bin/phpspec run
|
3 |
Do you want me to create `Petersuhm\Todo\Task` for you? y |
Menjalankan phpspec lagi, sesuatu yang menarik terjadi:
1 |
$ vendor/bin/phpspec run
|
2 |
Do you want me to create `Petersuhm\Todo\TaskCollection::add()` for you? y |
Sempurna! Jika Anda melihat file TaskCollection.php
, Anda akan melihat bahwa phpspec yang membuat fungsi add()
bagi kita untuk mengisi:
1 |
<?php
|
2 |
|
3 |
namespace Petersuhm\Todo; |
4 |
|
5 |
class TaskCollection |
6 |
{
|
7 |
|
8 |
public function add($argument1) |
9 |
{
|
10 |
// TODO: write logic here
|
11 |
}
|
12 |
}
|
phpspec yang masih mengeluh, meskipun. Kami tidak memiliki $tasks
array, jadi mari kita membuat satu dan menambahkan tugas untuk itu:
1 |
<?php
|
2 |
|
3 |
namespace Petersuhm\Todo; |
4 |
|
5 |
class TaskCollection |
6 |
{
|
7 |
public $tasks; |
8 |
|
9 |
public function add(Task $task) |
10 |
{
|
11 |
$this->tasks[] = $task; |
12 |
}
|
13 |
}
|
Sekarang spesifikasi kami semua bagus dan hijau. Perhatikan bahwa saya memastikan untuk typehint $task
parameter.
Hanya untuk memastikan kita mendapatkannya tepat, mari kita menambahkan task lain:
1 |
function it_adds_a_task_to_the_collection(Task $task, Task $anotherTask) |
2 |
{
|
3 |
$this->add($task); |
4 |
$this->tasks[0]->shouldBe($task); |
5 |
|
6 |
$this->add($anotherTask); |
7 |
$this->tasks[1]->shouldBe($anotherTask); |
8 |
}
|
Menjalankan phpspec, sepertinya kita sedang semua baik.
Mengimplementasikan interface Countable
Kami ingin tahu berapa banyak tugas dalam koleksi, yang merupakan alasan yang baik untuk menggunakan salah satu interface dari Standard PHP Library (SPL), yaitu interface Countable
. Interface ini menyatakan bahwa kelas mengimplementasikannya harus memiliki metode count()
.
Sebelumnya, kami menggunakan matcher shouldHaveType()
, yang merupakan jenis matcher. Menggunakan instanceof
komparator PHP untuk memvalidasi bahwa objek sebenarnya adalah instance class tertentu. Ada 4 jenis matchers, di mana semua melakukan hal yang sama. Salah satunya adalah shouldImplement()
, yang sempurna untuk tujuan kita, jadi mari kita pergi ke depan dan menggunakannya dalam sebuah contoh:
1 |
function it_is_countable() |
2 |
{
|
3 |
$this->shouldImplement('Countable'); |
4 |
}
|
Lihat betapa indah yang membaca? Mari kita menjalankan contoh dan memiliki phpspec yang memimpin jalan bagi kita:
1 |
$ vendor/bin/phpspec run
|
2 |
|
3 |
Petersuhm/Todo/TaskCollection |
4 |
25 ✘ is countable |
5 |
expected an instance of Countable, but got [obj:Petersuhm\Todo\TaskCollection]. |
Oke, jadi class kami bukan instance Countable
karena kita belum menerapkannya. Mari kita memperbarui kode untuk class TaskCollection
kami:
1 |
class TaskCollection implements \Countable |
Pengujian kami tidak berjalan, karena interface Countable
memiliki metode yang abstrak, count()
, yang kita miliki untuk menerapkan. Metode yang kosong akan melakukan trik untuk sekarang:
1 |
public function count() |
2 |
{
|
3 |
// ...
|
4 |
}
|
Dan kita kembali ke hijau. Saat ini metode count()
kami tidak berbuat banyak, dan itu benar-benar cukup berguna. Mari kita menulis spesifikasi untuk perilaku yang kami berharap untuk memiliki. Pertama, dengan tidak ada tugas, fungsi menghitung kita diharapkan untuk mengembalikan nol:
1 |
function it_counts_elements_of_the_collection() |
2 |
{
|
3 |
$this->count()->shouldReturn(0); |
4 |
}
|
Mengembalikan nilai null
, bukan 0
. Untuk mendapatkan tes hijau, mari kita memperbaiki hal ini dengan cara TDD.BDD:
1 |
public function count() |
2 |
{
|
3 |
return 0; |
4 |
}
|
sudah hijau dan semua itu baik, tapi ini tidak mungkin perilaku yang kita inginkan. Sebaliknya, mari kita memperluas spec kami dan menambahkan sesuatu ke $tasks
array:
1 |
function it_counts_elements_of_the_collection() |
2 |
{
|
3 |
$this->count()->shouldReturn(0); |
4 |
|
5 |
$this->tasks = ['foo']; |
6 |
$this->count()->shouldReturn(1); |
7 |
}
|
Tentu saja, kode kita masih mengembalikan 0
, dan kami memiliki langkah merah. Memperbaiki ini tidak terlalu sulit dan kelas TaskCollection
kami sekarang harus terlihat seperti ini:
1 |
<?php
|
2 |
|
3 |
namespace Petersuhm\Todo; |
4 |
|
5 |
class TaskCollection implements \Countable |
6 |
{
|
7 |
public $tasks; |
8 |
|
9 |
public function add(Task $task) |
10 |
{
|
11 |
$this->tasks[] = $task; |
12 |
}
|
13 |
|
14 |
public function count() |
15 |
{
|
16 |
return count($this->tasks); |
17 |
}
|
18 |
}
|
Kami memiliki tes hijau dan count()
metode bekerja. Hari apa ini!
Ekpetasi & harapan
Ingat saya katakan bahwa phpspec memungkinkan Anda untuk hal keren dengan contoh class Collaborator
, alias contoh yang secara otomatis disuntikkan oleh phpspec? Jika Anda telah menulis unit test sebelumnya, Anda pasti tahu apa itu mock dan stub. Jika Anda tidak, jangan khawatir terlalu banyak tentang hal itu. Hal ini hanya jargon. Hal ini mengacu pada "fake" objek yang akan bertindak sebagai objek nyata Anda, tetapi memungkinkan Anda untuk menguji dalam isolasi. phpspec akan secara otomatis berganti kepada Collaborator
iinstance ke mock dan stub: jika Anda membutuhkannya dalam spesifikasi Anda.
Ini benar-benar mengagumkan. Di belakang layar, phpspec menggunakan perpustakaan Prophecy, yang adalah framework mocking sangat dogmatis yang bermain baik dengan phpspec (dan dibuat oleh orang-orang luar biasa yang sama). Anda dapat menetapkan ekpetasi pada kolaborator (mocking), seperti "metode harus dipanggil", dan Anda dapat menambahkan janji-janji (stubbing), seperti "metode ini akan mengembalikan nilai ini". Dengan phpspec ini benar-benar mudah dan kami akan melakukan hal-hal kedua berikutnya.
Mari kita membuat class, kita akan menyebutnya TodoList
, yang dapat membuat penggunaan class koleksi kami.
1 |
$ vendor/bin/phpspec desc "Petersuhm\Todo\TodoList" |
2 |
$ vendor/bin/phpspec run
|
3 |
Do you want me to create `Petersuhm\Todo\TodoList` for you? y |
Menambahkan Task
Contoh pertama kami akan menambahkan, adalah salah satu untuk menambahkan task. Kami akan membuat addTask()
metode, yang tidak melakukan apa lebih dari menambahkan tugas untuk koleksi kami. Ini hanya mengarahkan memanggil ke metode add()
pada koleksi, jadi ini adalah tempat yang sempurna untuk membuat penggunaan ekpetasi. Kita tidak ingin metode untuk benar-benar memanggil metode add()
, kami hanya ingin memastikan bahwa mencoba untuk melakukannya. Selain itu, kami ingin memastikan bahwa ini hanya sekali dipanggil. Lihatlah bagaimana kita bisa pergi tentang hal ini dengan phpspec:
1 |
<?php
|
2 |
|
3 |
namespace spec\Petersuhm\Todo; |
4 |
|
5 |
use PhpSpec\ObjectBehavior; |
6 |
use Prophecy\Argument; |
7 |
use Petersuhm\Todo\TaskCollection; |
8 |
use Petersuhm\Todo\Task; |
9 |
|
10 |
class TodoListSpec extends ObjectBehavior |
11 |
{
|
12 |
function it_is_initializable() |
13 |
{
|
14 |
$this->shouldHaveType('Petersuhm\Todo\TodoList'); |
15 |
}
|
16 |
|
17 |
function it_adds_a_task_to_the_list(TaskCollection $tasks, Task $task) |
18 |
{
|
19 |
$tasks->add($task)->shouldBeCalledTimes(1); |
20 |
$this->tasks = $tasks; |
21 |
|
22 |
$this->addTask($task); |
23 |
}
|
24 |
}
|
Pertama, kita memiliki phpspec menyediakan kami dengan dua kolaborator kami membutuhkan: kumpulan tugas dan tugas. Kemudian kita menetapkan harapan pada tugas koleksi kolaborator pada dasarnya mengatakan: "metode add()
harus dipanggil persis 1 kali dengan variabel $task
sebagai parameter". Ini adalah bagaimana kita mempersiapkan kolaborator kami, yang sekarang mock, sebelum kita menetapkannya ke properti $tasks
di TodoList
. Akhirnya, kami mencoba untuk benar-benar memanggil metode addTask()
.
OK, phpspec Apakah mengatakan tentang ini:
1 |
$ vendor/bin/phpspec run
|
2 |
|
3 |
Petersuhm/Todo/TodoList |
4 |
17 ! adds a task to the list
|
5 |
property tasks not found. |
Properti $tasks
ini tidak ada - mudah:
1 |
<?php
|
2 |
|
3 |
namespace Petersuhm\Todo; |
4 |
|
5 |
class TodoList |
6 |
{
|
7 |
public $tasks; |
8 |
}
|
Coba lagi, dan memiliki panduan cara kami phpspec:
1 |
$ vendor/bin/phpspec run
|
2 |
Do you want me to create `Petersuhm\Todo\TodoList::addTask()` for you? y |
3 |
$ vendor/bin/phpspec run
|
4 |
|
5 |
Petersuhm/Todo/TodoList |
6 |
17 ✘ adds a task to the list |
7 |
some predictions failed: |
8 |
Double\Petersuhm\Todo\TaskCollection\P4: |
9 |
Expected exactly 1 calls that match: |
10 |
Double\Petersuhm\Todo\TaskCollection\P4->add(exact(Double\Petersuhm\Todo\Task\P3:000000002544d76d0000000059fcae53)) |
11 |
but none were made. |
Oke, sekarang sesuatu yang menarik terjadi. Melihat pesan "Expected exactly 1 calls that match:..."? Ini adalah harapan gagal kami. Hal ini terjadi karena setelah memanggil metode addTask()
, metode add()
pada koleksi tidak dipanggil, yang kami harapkan hal itu terjadi.
Untuk mendapatkan kembali ke green, isi kode berikut dalam metode kosong addTask():
1 |
<?php
|
2 |
|
3 |
namespace Petersuhm\Todo; |
4 |
|
5 |
class TodoList |
6 |
{
|
7 |
public $tasks; |
8 |
|
9 |
public function addTask(Task $task) |
10 |
{
|
11 |
$this->tasks->add($task); |
12 |
}
|
13 |
}
|
Kembali ke hijau! Rasanya enak, benar?
Memeriksa untuk Task
Mari kita lihat pada janji-janji juga. Kami ingin metode yang dapat memberitahu kami jika ada tugas apapun dalam koleksi. Untuk ini, kita akan hanya memeriksa nilai kembali metode count()
pada koleksi. Sekali lagi, kita tidak perlu instance asli dengan metode count()
asli. Kita hanya perlu untuk memastikan bahwa kode kita memanggil metode count()
beberapa dan melakukan beberapa hal tergantung pada nilai kembalian.
Lihatlah contoh berikut:
1 |
function it_checks_whether_it_has_any_tasks(TaskCollection $tasks) |
2 |
{
|
3 |
$tasks->count()->willReturn(0); |
4 |
$this->tasks = $tasks; |
5 |
|
6 |
$this->hasTasks()->shouldReturn(false); |
7 |
}
|
Kami memiliki tugas kolaborator koleksi yang memiliki metode count()
yang akan mengembalikan nilai nol. Ini adalah janji kami. Apakah ini berarti bahwa setiap kali seseorang memanggil metode count()
, itu akan mengmbalikan nilai nol. Kami kemudian menetapkan kolaborator untuk properti $tasks
pada objek. Akhirnya, kami mencoba untuk memanggil metode, hasTasks()
, dan membuat yakin itu mengembalikan nilai false
.
Apa phspec harus katakan tentang hal ini?
1 |
$ vendor/bin/phpspec run
|
2 |
Do you want me to create `Petersuhm\Todo\TodoList::hasTasks()` for you? y |
3 |
$ vendor/bin/phpspec run
|
4 |
|
5 |
Petersuhm/Todo/TodoList |
6 |
25 ✘ checks whether it has any tasks |
7 |
expected false, but got null.
|
Dingin. phpspec membuat kita hasTasks()
metode dan tidak mengherankan, mengembalikan null
, bukan false
.
Sekali lagi, ini adalah salah satu yang mudah untuk memperbaiki:
1 |
public function hasTasks() |
2 |
{
|
3 |
return false; |
4 |
}
|
Kami kembali ke hijau, tetapi hal ini tidak cukup apa yang kita inginkan. Mari kita periksa untuktask ketika ada 20 dari mereka. Ini harus mengembalikan nilai true
:
1 |
function it_checks_whether_it_has_any_tasks(TaskCollection $tasks) |
2 |
{
|
3 |
$tasks->count()->willReturn(0); |
4 |
$this->tasks = $tasks; |
5 |
|
6 |
$this->hasTasks()->shouldReturn(false); |
7 |
|
8 |
$tasks->count()->willReturn(20); |
9 |
$this->tasks = $tasks; |
10 |
|
11 |
$this->hasTasks()->shouldReturn(true); |
12 |
}
|
Menjalankan phspec dan kami akan mendapatkan:
1 |
$ vendor/bin/phpspec run
|
2 |
|
3 |
Petersuhm/Todo/TodoList |
4 |
25 ✘ checks whether it has any tasks |
5 |
expected true, but got false.
|
Oke, false
bukan true
, jadi kita perlu memperbaiki kode kita. Mari kita menggunakan metode count()
untuk melihat apakah ada task atau tidak:
1 |
public function hasTasks() |
2 |
{
|
3 |
if ($this->tasks->count() > 0) |
4 |
return true; |
5 |
|
6 |
return false; |
7 |
}
|
Tah dah! Kembali ke hijau!
Bangunan kustom Matchers
Bagian menulis spesifikasi yang baik adalah untuk membuat mereka sebagai mudah dibaca mungkin. Contoh terakhir kami benar-benar akan meningkat sedikit, berkat phpspec's matchers kustom. Sangat mudah untuk menerapkan kustom matchers - semua harus kita lakukan adalah untuk menimpa getMatchers()
metode yang merupakan warisan dari ObjectBehavior
. Dengan menerapkan dua matchers kustom, spesifikasi kami dapat diubah untuk terlihat seperti ini:
1 |
function it_checks_whether_it_has_any_tasks(TaskCollection $tasks) |
2 |
{
|
3 |
$tasks->count()->willReturn(0); |
4 |
$this->tasks = $tasks; |
5 |
|
6 |
$this->hasTasks()->shouldBeFalse(); |
7 |
|
8 |
$tasks->count()->willReturn(20); |
9 |
$this->tasks = $tasks; |
10 |
|
11 |
$this->hasTasks()->shouldBeTrue(); |
12 |
}
|
13 |
|
14 |
function getMatchers() |
15 |
{
|
16 |
return [ |
17 |
'beTrue' => function($subject) { |
18 |
return $subject === true; |
19 |
},
|
20 |
'beFalse' => function($subject) { |
21 |
return $subject === false; |
22 |
},
|
23 |
];
|
24 |
}
|
Saya pikir ini terlihat cukup bagus. Ingat, bahwa refactoring spesifikasi Anda penting untuk menjaga mereka tetap up-to-date. Menerapkan matchers kustom Anda sendiri dapat membersihkan spesifikasi Anda dan membuat mereka lebih mudah dibaca.
Sebenarnya, kita dapat menggunakan negasi terhadap matchers juga:
1 |
function it_checks_whether_it_has_any_tasks(TaskCollection $tasks) |
2 |
{
|
3 |
$tasks->count()->willReturn(0); |
4 |
$this->tasks = $tasks; |
5 |
|
6 |
$this->hasTasks()->shouldNotBeTrue(); |
7 |
|
8 |
$tasks->count()->willReturn(20); |
9 |
$this->tasks = $tasks; |
10 |
|
11 |
$this->hasTasks()->shouldNotBeFalse(); |
12 |
}
|
Ya. Cukup keren!
Kesimpulan
Semua spesifikasi kami hijau dan melihat seberapa baik mereka dokumen kode kita!
1 |
Petersuhm\Todo\TaskCollection |
2 |
|
3 |
10 ✔ is initializable |
4 |
15 ✔ adds a task to the collection |
5 |
24 ✔ is countable |
6 |
29 ✔ counts elements of the collection |
7 |
|
8 |
Petersuhm\Todo\Task |
9 |
|
10 |
10 ✔ is initializable |
11 |
|
12 |
Petersuhm\Todo\TodoList |
13 |
|
14 |
11 ✔ is initializable |
15 |
16 ✔ adds a task to the list |
16 |
24 ✔ checks whether it has any tasks |
17 |
|
18 |
|
19 |
3 specs |
20 |
8 examples (8 passed) |
21 |
16ms |
Kami memiliki secara efektif dijelaskan dan mencapai perilaku yang diinginkan dari kode kita. Bukan untuk menyebutkan, kode kami adalah 100% ditutupi oleh spesifikasi kami, yang berarti bahwa refactoring tidak menakutkan menyebkan pengalaman.
Dengan mengikuti dari awal, saya berharap kau terinspirasi untuk memberikan phpspec mencoba. Lebih dari pengujian ini tool desain. Setelah Anda terbiasa untuk menggunakan phpspec (dan ini tool kode genearation keren), Anda akan memiliki waktu sulit melepaskan itu lagi! Orang sering mengeluh bahwa melakukan TDD atau BDD memperlambat mereka. Setelah memasukkan phpspec di alur kerja saya, saya benar-benar merasa sebaliknya - produktivitas saya secara signifikan ditingkatkan. Dan kode saya lebih solid!