Advertisement
  1. Code
  2. PHP
  3. Laravel

Laravel, BDD dan Anda: Mari kita mulai

Scroll to top
Read Time: 13 min
This post is part of a series called Laravel, BDD And You.
Laravel, BDD and You: The First Feature

() translation by (you can also view the original English article)

Selamat datang di seri ini tentang mengembangkan aplikasi Laravel menggunakanbehavior-driven development (BDD). Full stack BDD dapat tampak rumit dan menakutkan. Ada cara yang sama seperti banyak melakukan hal itu karena ada pengembang.

Dalam seri ini, saya akan memandu Anda melalui pendekatan saya menggunakan Behat dan PhpSpec untuk desain Laravel aplikasi dari awal.

Ada banyak resource untuk BDD secara umum, tapi bahan tertentu Laravel sulit untuk menemukan. Oleh karena itu, dalam seri ini, kita akan fokus lebih pada Laravel terkait aspek dan kurang pada hal-hal umum yang Anda dapat membaca tentang tempat-tempat lain.

Describing Behavior

Ketika menggambarkan behavior, yang juga dikenal sebagai menulis cerita dan spesifikasi, kita akan menggunakan pendekatan outside-in Ini berarti bahwa setiap kali kita membangun fitur baru, kita akan mulai dengan menulis kisah pengguna secara keseluruhan. Hal ini biasanya dari perspektif klien atau stakeholders lainnya.

Apa kita mengharapkan terjadi ketika kita melakukan ini?

Kami tidak diperbolehkan untuk menulis kode apapun sampai kita telah gagal, langkah merah misalnya, kecuali kita adalah refactoring kode yang sudah ada.

Kadang-kadang, maka akan diperlukan untuk iteratively memecahkan sebagian kecil dari cerita atau fitur (dua kata yang saya gunakan secara bergantian) di mana kita bekerja. Ini sering berarti menulis spesifikasi dengan PhpSpec. Kadang-kadang ini akan memakan banyak iterasi pada tingkat integrasi atau unit sebelum seluruh cerita (pada tingkat penerimaan) adalah passing. Ini semua terdengar sangat rumit tapi sebenarnya tidak. Saya percaya besar dengan learning by doing, jadi saya berpikir bahwa segala sesuatu akan membuat lebih masuk akal sekali kita mulai menulis beberapa code yang sebenarnya.

Kami akan menulis cerita dan spesifikasi pada empat tingkat yang berbeda:

1. Acceptance

Sebagian besar waktu, suite fungsional kami akan berfungsi sebagai acceptance layer. Cara kami akan menggambarkan fitur kami di suite fungsional akan sangat mirip dengan bagaimana kita akan menulis acceptance story (menggunakan automated browser framework) dan dengan demikian akan membuat banyak duplikasi.

Sebagai cerita yang menggambarkan perilaku dari klien,sudut pandang, mereka melayani sebagai acceptance story. Kami akan menggunakan Symfony DomCrawler untuk menguji output dari aplikasi kita. Kemudian dalam seri ini, kita mungkin menemukan bahwa kita perlu untuk menguji melalui browser yang sebenarnya yang dapat menjalankan JavaScript juga. Pengujian melalui browser menambahkan beberapa kekhawatiran baru, karena kita perlu memastikan bahwa kami beban lingkungan pengujian jam ketika suite dijalankan.

2. Functional

Di functional suite, kita akan memiliki akses ke aplikasi Laravel, yang sangat nyaman. Pertama-tama, itu membuat mudah untuk membedakan antara environment. Kedua dari semua, tidak akan melalui browser membuat test suite kami jauh lebih cepat. Setiap kali kita ingin menerapkan fitur baru, kami akan menulis sebuah cerita di functional suite menggunakan Behat.

3. Integration

Integration suite kita akan menguji perilaku bagian inti dari aplikasi kita yang tidak selalu perlu untuk memiliki akses ke Laravel. Suite integrasi biasanya akan campuran Behat story dan PhpSpec spesifikasi.

4. Unit

Unit tes kita akan ditulis dalam PhpSpec dan akan dites terisolasi kecil unit inti aplikasi. Entity kami, value objek dll semua memiliki spesifikasi.

The Case

Sepanjang seri ini, mulai dari artikel berikutnya, kami akan membangun sebuah sistem untuk melacak waktu. Kita akan mulai dengan menggambarkan perilaku dari luar dengan menulis Behat fitur. Perilaku internal aplikasi kita akan dijelaskan menggunakan PhpSpec.

Bersama dua tool itu akan membantu kita merasa nyaman dengan kualitas aplikasi yang sedang kita bangun. Kami terutama akan menulis fitur dan spesifikasi pada tiga level:

  1. Fungsional
  2. Integration
  3. Unit


Di suite kami fungsional, kami akan crawl HTTP response dari aplikasi kita dalam mode headless, berarti bahwa kita tidak akan pergi melalui browser. Ini akan membuat lebih mudah untuk berinteraksi dengan Laravel dan membuat suite kami fungsional yang berfungsi sebagai acceptance layer, juga.

Kemudian jika kita akhirnya memiliki UI yang lebih rumit dan mungkin perlu untuk menguji beberapa JavaScript juga, kita bisa menambahkan sebuah acceptance suite. Seri ini masih karya dalam proses, jadi jangan ragu untuk memberi saran Anda di bagian komentar.

Pengaturan kita

Perhatikan bahwa untuk tutorial ini, saya menganggap Anda memiliki instalasi baru dari Laravel (4.2) dan berjalan. Sebaiknya Anda menggunakan Laravel Homestead juga, yang adalah apa yang saya gunakan ketika saya menulis kode ini.

Sebelum kita mulai dengan pekerjaan nyata, mari kita pastikan kita memiliki Behat dan PhpSpec dan berjalan. Pertama walaupun, saya ingin melakukan sedikit membersihkan setiap kali aku memulai sebuah proyek laravel baru dan menghapus hal-hal yang kurang diperlukan:

1
git rm -r app/tests/ phpunit.xml CONTRIBUTING.md

Jika Anda menghapus file-file ini, pastikan untuk memperbarui file composer.json Anda seperti:

1
"autoload": {
2
    "classmap": [
3
        "app/commands",
4
        "app/controllers",
5
        "app/models",
6
        "app/database/migrations",
7
        "app/database/seeds"
8
    ]
9
},

Dan, tentu saja:

1
$ composer dump-autoload

Sekarang kita siap untuk menarik alat BDD yang kami butuhkan. Cukup tambahkan bagian require-dev ke composer.json Anda:

1
"require": {
2
    "laravel/framework": "4.2.*"
3
},
4
"require-dev": {
5
    "behat/behat": "~3.0",
6
    "phpspec/phpspec": "~2.0",
7
    "phpunit/phpunit": "~4.1"
8
},

"Mengapa kita pulling PHPUnit?" Anda mungkin berpikir? Kami tidak akan menulis baik ol ' PHPUnit uji kasus dalam seri ini, tapi pernyataan adalah tool yang berguna bersama-sama dengan Behat. Kita akan melihat bahwa nanti dalam artikel ini ketika kita menulis fitur pertama kami.

Ingat untuk memperbarui Anda dependensi setelah memodifikasi composer.json:

1
$ composer update --dev

Kita hampir selesai menginstal dan mengatur tool. PhpSpec bekerja seperti seharusnya:

1
$ vendor/bin/phpspec run
2
3
0 specs
4
0 examples 
5
0ms

Tetapi Behat perlu melakukan lari cepat dengan opsi--init untuk menyiapkan segalanya:

1
$ vendor/bin/behat --init
2
3
+d features - place your *.feature files here
4
+d features/bootstrap - place your context classes here
5
+f features/bootstrap/FeatureContext.php - place your definitions, transformations and hooks here
6
7
$ vendor/bin/behat
8
9
No scenarios
10
No steps
11
0m0.14s (12.18Mb)

Perintah yang pertama dibuat mengkilap baru FeatureContext kelas, dimana kita dapat menulis definisi langkah yang diperlukan untuk fitur kami:

1
<?php
2
3
use Behat\Behat\Context\SnippetAcceptingContext;
4
use Behat\Gherkin\Node\PyStringNode;
5
use Behat\Gherkin\Node\TableNode;
6
7
/**

8
 * Behat context class.

9
 */
10
class FeatureContext implements SnippetAcceptingContext
11
{
12
    /**

13
     * Initializes context.

14
     *

15
     * Every scenario gets its own context object.

16
     * You can also pass arbitrary arguments to the context constructor through behat.yml.

17
     */
18
    public function __construct()
19
    {
20
    }
21
}

Menulis fitur pertama kami

Fitur pertama kami akan sangat sederhana: kita hanya akan membuat yakin bahwa instalasi Laravel baru kami menyambut kami dengan "You have arrived" pada homepage. Aku meletakkan di agak konyol Given langkah juga, Given I am logged in, yang hanya berfungsi untuk menunjukkan betapa mudahnya berinteraksi dengan Laravel di fitur kami.

Secara teknis, saya akan mengkategorikan jenis fitur sebagai functional test, karena ia berinteraksi dengan framework, tetapi juga berfungsi sebagai acceptance test, karena kita tidak akan melihat apapun hasil yang berbeda dari menjalankan tes serupa melalui browser alat pengujian. Untuk sekarang kita akan menempel dengan functional test suite.

Langsung saja dan membuat welcome.feature file dan meletakkannya di features/functional:

1
# features/functional/welcome.feature
2
3
Feature: Welcoming developer
4
    As a Laravel developer
5
    In order to proberly begin a new project
6
    I need to be greeted upon arrival
7
8
    Scenario: Greeting developer on homepage
9
        Given I am logged in
10
        When I visit "/"
11
        Then I should see "You have arrived."

Dengan meletakkan fitur fungsional dalam direktori functional, akan lebih mudah bagi kita untuk mengelola suite kami kemudian. Kami tidak ingin integrasi jenis fitur yang tidak memerlukan Laravel harus menunggu untuk suite fungsional lambat.

Saya suka menjaga hal-hal bagus dan bersih, jadi saya percaya kita harus memiliki fitur khusus konteks untuk functional suite  yang dapat memberikan kami akses ke Laravel. Anda hanya dapat pergi ke depan dan salin file FeatureContext yang sudah ada dan mengubah nama kelas untuk LaravelFeatureContext. Untuk pekerjaan ini, kita juga perlu file konfigurasi behat.yml.

Membuat satu dalam direktori root dari proyek Anda dan tambahkan berikut:

1
default:
2
    suites:
3
        functional:
4
            paths: [ %paths.base%/features/functional ]
5
            contexts: [ LaravelFeatureContext ]

Saya pikir YAML di sini adalah diri cukup jelas. functional suitekami akan mencari fitur dalam direktori functional dan menjalankan mereka melalui LaravelFeatureContext.

Jika kita mencoba untuk menjalankan Behat saat ini, ini akan memberitahu kita untuk melaksanakan definisi langkah penting. Kita dapat memiliki Behat menambahkan metode scaffold kosong ke LaravelFeatureContext dengan perintah berikut:

1
$ vendor/bin/behat --dry-run --append-snippets
2
$ vendor/bin/behat
3
4
Feature: Welcoming developer
5
    As a Laravel developer
6
    In order to proberly begin a new project
7
    I need to be greeted upon arival
8
9
  Scenario: Greeting developer on homepage # features/functional/welcome.feature:6

10
    Given I am logged in                   # LaravelFeatureContext::iAmLoggedIn()

11
      TODO: write pending definition
12
    When I visit "/"                       # LaravelFeatureContext::iVisit()

13
    Then I should see "You have arrived."  # LaravelFeatureContext::iShouldSee()

14
15
1 scenario (1 pending)
16
3 steps (1 pending, 2 skipped)
17
0m0.28s (12.53Mb)

Dan sekarang, seperti yang Anda lihat dari Keluaran, kami siap untuk mulai melaksanakan pertama dari langkah kami: Given I am logged in.

Kasus uji PHPUnit yang kapal dengan Laravel memungkinkan kita untuk melakukan hal-hal seperti $this->be($user), yang log in pengguna tertentu. Pada akhirnya, kami ingin dapat berinteraksi dengan Laravel seolah-olah kami menggunakan PHPUnit, jadi mari kita pergi ke depan dan menulis kode definisi langkah "we wish we had":

1
/**

2
 * @Given I am logged in

3
 */
4
public function iAmLoggedIn()
5
{
6
    $user = new User;
7
8
    $this->be($user);
9
}

Ini tidak akan bekerja tentu saja, karena Behat tidak tahu tentang hal-hal tertentu Laravel, tapi saya akan menunjukkan Anda dalam hanya kedua cara mudah untuk mendapatkan Behat dan Laravel untuk bermain dengan baik bersama-sama.

Jika Anda melihat di sumber Laravel dan menemukan Illuminate\Foundation\Testing\TestCase kelas, yaitu kelas yang kasus uji standar meluas dari, Anda akan melihat bahwa mulai dari Laravel 4.2, semuanya telah dipindahkan ke sifat. ApplicationTrait sekarang bertanggung jawab untuk booting instance Application, pengaturan klien HTTP dan memberi kita beberapa metode helper, seperti be().

Ini keren, terutama karena itu berarti bahwa kita dapat hanya menarik itu untuk konteks Behat kami dengan hampir tidak ada setup yang diperlukan. Kami juga memiliki akses ke AssertionsTrait, tetapi ini masih terikat PHPUnit.

Ketika kita menarik trait, kita perlu untuk melakukan dua hal. Kita perlu memiliki setUp() metode, seperti di Illuminate\Foundation\Testing\TestCase kelas, dan kami memerlukan createApplication() metode, seperti di standar Laravel uji kasus. Benar-benar kita dapat hanya menyalin dua metode dan menggunakannya langsung.

Ada hanya satu hal perlu diperhatikan: di PHPUnit, setUp() metode akan secara otomatis dipanggil sebelum setiap tes. Untuk mencapai hal yang sama dalam Behat, kita dapat menggunakan anotasi @BeforeScenario.

Tambahkan baris berikut ke LaravelFeatureContext Anda:

1
use Illuminate\Foundation\Testing\ApplicationTrait;
2
3
/**

4
 * Behat context class.

5
 */
6
class LaravelFeatureContext implements SnippetAcceptingContext
7
{
8
    /**

9
     * Responsible for providing a Laravel app instance.

10
     */
11
    use ApplicationTrait;
12
13
    /**

14
     * Initializes context.

15
     *

16
     * Every scenario gets its own context object.

17
     * You can also pass arbitrary arguments to the context constructor through behat.yml.

18
     */
19
    public function __construct()
20
    {
21
    }
22
23
    /**

24
     * @BeforeScenario

25
     */
26
    public function setUp()
27
    {
28
        if ( ! $this->app)
29
        {
30
            $this->refreshApplication();
31
        }
32
    }
33
34
    /**

35
     * Creates the application.

36
     *

37
     * @return \Symfony\Component\HttpKernel\HttpKernelInterface

38
     */
39
    public function createApplication()
40
    {
41
        $unitTesting = true;
42
43
        $testEnvironment = 'testing';
44
45
        return require __DIR__.'/../../bootstrap/start.php';
46
    }

Cukup mudah, dan lihat apa yang kita dapatkan ketika kita menjalankan Behat:

1
$ vendor/bin/behat
2
3
Feature: Welcoming developer
4
    As a Laravel developer
5
    In order to proberly begin a new project
6
    I need to be greeted upon arival
7
8
  Scenario: Greeting developer on homepage # features/functional/welcome.feature:6

9
    Given I am logged in                   # LaravelFeatureContext::iAmLoggedIn()

10
    When I visit "/"                       # LaravelFeatureContext::iVisit()

11
      TODO: write pending definition
12
    Then I should see "You have arrived."  # LaravelFeatureContext::iShouldSee()

13
14
1 scenario (1 pending)
15
3 steps (1 passed, 1 pending, 1 skipped)
16
0m0.73s (17.92Mb)

Hijau langkah pertama, yang berarti bahwa kami setup bekerja!

Berikutnya, kita dapat menerapkan When I visit step. Ini super mudah, dan kita dapat menggunakan call() metode yang menyediakan ApplicationTrait. Satu baris kode akan membuat kita di sana:

1
/**

2
 * @When I visit :uri

3
 */
4
public function iVisit($uri)
5
{
6
    $this->call('GET', $uri);
7
}

Langkah terakhir, Then I should see, mengambil sedikit lebih dan kita perlu untuk menarik dua dependensi. Kita perlu PHPUnit untuk assertion dan kita akan membutuhkan Symfony DomCrawler untuk mencari teks "You have arrived.".

Kita dapat menerapkan seperti ini:

1
use PHPUnit_Framework_Assert as PHPUnit;
2
use Symfony\Component\DomCrawler\Crawler;
3
4
...
5
6
/**

7
 * @Then I should see :text

8
 */
9
public function iShouldSee($text)
10
{
11
    $crawler = new Crawler($this->client->getResponse()->getContent());
12
13
    PHPUnit::assertCount(1, $crawler->filterXpath("//text()[. = '{$text}']"));
14
}

Ini adalah cukup banyak kode yang sama seperti Anda akan menulis jika Anda menggunakan PHPUnit. Bagian filterXpath() sedikit membingungkan dan kami akan tidak khawatir tentang hal itu sekarang, karena itu keluar sedikit dari lingkup artikel ini. Percaya saja kepadaku bahwa ia bekerja.

Menjalankan Behat satu kali akhir adalah kabar baik:

1
$ vendor/bin/behat
2
Feature: Welcoming developer
3
    As a Laravel developer
4
    In order to proberly begin a new project
5
    I need to be greeted upon arival
6
7
  Scenario: Greeting developer on homepage # features/functional/welcome.feature:6

8
    Given I am logged in                   # LaravelFeatureContext::iAmLoggedIn()

9
    When I visit "/"                       # LaravelFeatureContext::iVisit()

10
    Then I should see "You have arrived."  # LaravelFeatureContext::iShouldSee()

11
12
1 scenario (1 passed)
13
3 steps (3 passed)
14
0m0.82s (19.46Mb)

Fitur ini bekerja seperti yang diharapkan dan pengembang disambut pada saat kedatangan.

Kesimpulan

LaravelFeatureContext lengkap sekarang harus terlihat seperti ini:

1
<?php
2
3
use Behat\Behat\Context\SnippetAcceptingContext;
4
use Behat\Gherkin\Node\PyStringNode;
5
use Behat\Gherkin\Node\TableNode;
6
7
use PHPUnit_Framework_Assert as PHPUnit;
8
use Symfony\Component\DomCrawler\Crawler;
9
10
use Illuminate\Foundation\Testing\ApplicationTrait;
11
12
/**

13
 * Behat context class.

14
 */
15
class LaravelFeatureContext implements SnippetAcceptingContext
16
{
17
    /**

18
     * Responsible for providing a Laravel app instance.

19
     */
20
    use ApplicationTrait;
21
22
    /**

23
     * Initializes context.

24
     *

25
     * Every scenario gets its own context object.

26
     * You can also pass arbitrary arguments to the context constructor through behat.yml.

27
     */
28
    public function __construct()
29
    {
30
    }
31
32
    /**

33
     * @BeforeScenario

34
     */
35
    public function setUp()
36
    {
37
        if ( ! $this->app)
38
        {
39
            $this->refreshApplication();
40
        }
41
    }
42
43
    /**

44
     * Creates the application.

45
     *

46
     * @return \Symfony\Component\HttpKernel\HttpKernelInterface

47
     */
48
    public function createApplication()
49
    {
50
        $unitTesting = true;
51
52
        $testEnvironment = 'testing';
53
54
        return require __DIR__.'/../../bootstrap/start.php';
55
    }
56
57
    /**

58
     * @Given I am logged in

59
     */
60
    public function iAmLoggedIn()
61
    {
62
        $user = new User;
63
64
        $this->be($user);
65
    }
66
67
    /**

68
     * @When I visit :uri

69
     */
70
    public function iVisit($uri)
71
    {
72
        $this->call('GET', $uri);
73
    }
74
75
    /**

76
     * @Then I should see :text

77
     */
78
    public function iShouldSee($text)
79
    {
80
        $crawler = new Crawler($this->client->getResponse()->getContent());
81
82
        PHPUnit::assertCount(1, $crawler->filterXpath("//text()[. = '{$text}']"));
83
    }
84
}

Kami sekarang memiliki dasar yang benar-benar baik untuk membangun kita terus mengembangkan aplikasi Laravel baru kami menggunakan BDD. Saya berharap saya telah membuktikan kepada Anda betapa mudahnya untuk mendapatkan Laravel dan Behat untuk bermain dengan baik bersama-sama.

Kami telah menyentuh pada banyak topik yang berbeda dalam artikel yang pertama. Tidak perlu khawatir, kita akan melihat lebih mendalam semuanya sebagai seri terus. Jika Anda memiliki pertanyaan atau saran, silakan tinggalkan komentar.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.