3.2.4.1.Các sự kiện trong Behat
Quá trình thực hiện các kiểm thử tự động Behat cung cấp một loạt các sự kiện để làm việc. Các sự kiện chính trong Behat đƣợc mô tả theo Hình 3-4[8].
Đầu tiên Behat đọc tất cả các tính năng đã đƣợc viết trong các tập tin .feature đặt trong thƣ mục features.
Sau khi đọc tính năng, Behat sẽ phân tích các tính năng theo ngôn ngữ Gherkin đƣa ra các cây cú pháp trừu tƣợng cho các tính năng đó
Tiếp đến, Behat chuyển cây cú pháp của mỗi tính năng thành các kiểm thử tính năng.
Các kiểm thử tính năng lấy các kịch bản của các tính năng đó để xây dựng thành các kịch bảnkiểm thử.
Các kịch bảnkiểm thử khởi tạo một đối tƣợng ngữ cảnh trong lớp FeatureContext và thông qua đó xác định các kiểm thử bƣớc của kịch bản hay các bƣớc của kịch bản nền.
Các kiểm thử bƣớc tìm các phƣơng thức định nghĩa bƣớc tƣơng ứng trong lớp FeatureContext để thực hiện chúng.
Hình 3-4. Các sự kiện Hook của Behat
Behat thực hiện cho đến khi kết thúc bƣớc cuối cùng của kịch bản cuối cùng trong tính năng đƣa vào. Tuy nhiên việc đƣa ra kết quả trên màn hình dòng lệnh và sau đó là trả ra các kết quả thống kê việc kiểm thử các bƣớc, các kịch bản và tính năng đó phải nhờ vào các sự kiện. Tại mỗi điểm thực hiện, các kiểm thử khởi tạo các đối tƣợng đặc biệt gọi là các sự kiện và gửi thông tin đến đối tƣợng EventDispatcher. Một tập các đối tƣợng khác gọi là Listeners sẽđăng ký nhận thông tin thông qua EventDispatcher, EventDispatcher sẽ tự động nhận các thông báo của các sự kiện để chuyển cho các Listenersđã đăng ký xử lý (Hình 3-4. Các sự kiện Hook của Behat).
3.2.4.2.Hooks
Behat cung cấp tám loại sự kiện để móc nối
Sự kiện BeforeSuite: Xảy ra trƣớc khi các tính năng trong dãy thực hiện. Sự kiện này có thể đƣợc sử dụng để thiết lập hệ thống đang kiểm thử. Sự kiện này đi kèm với một đối tƣợng của lớp Behat\Behat\Event\SuiteEvent.
Sự kiện AfterSuitexảy ra sau khi tất cả các tính năng trong dãy thực hiện. Sự kiện này đƣợc sử dụng đểin các thống kê, nó thƣờng đi kèm với một thể hiện của lớp Behat\Behat\Event\SuiteEvent.
Sự kiện BeforeFeaturexảy ra trƣớc khi một tính năng đƣợc thực hiện. Sự kiện nàyđi kèm một thể hiện của lớp Behat\Behat\Event\FeatureEvent.
Sự kiệnAfterFeaturexảy ra sau khi Behat thực hiện xong một tính năng.Sự kiện này đi kèm với một thể hiện của lớp Behat\Behat\Event\FeatureEvent.
Sự kiện BeforeScenario xảy ra trƣớc khi một kịch bản cụ thể đƣợc thực hiện. Sự kiện này đi kèm với một thể hiện của lớp Behat\Behat\EventScenarioEvent.
Sự kiện AfterScenario xảy ra sau khi Behat thực hiện xong một kịch bản. Sự kiện này đi kèm với một thể hiện của lớp Behat\Behat\Event\ScenarioEvent.
Sự kiện BeforeStepxảy ra trƣớc khi một bƣớc cụ thể đƣợc thực hiện. Sự kiện này đi kèm với một thể hiện của lớp Behat\Behat\Event\StepEvent.
Sự kiện AfterStepxảy ra sau khi Behat thực hiện xong một bƣớc. Sự kiện này đi kèm với một thể hiện của lớp Behat\Behat\Event\StepEvent.
3.2.5. Kiểm thử các tính năng – lớp FeatureContext
Lớp FeatureContext hay còn gọi là lớp ngƣ̃ cảnh là lớp đƣợc sƣ̉ dụng để đi ̣nh nghĩa các phƣơng thức kiểm thử bằng ngôn ngữ PHP tƣơng ứng với các đi ̣nh nghĩa bƣớc trong tƣ̀ng kịch bản. Tƣ̀ tâ ̣p tính năng, Behat sẽ tự động sinh ra các phƣơng thức kiểm thử tƣơng ứng với mỗi bƣớc. Tất cả các định nghĩa bƣớc cũng nhƣ các sự kiện cần thiết cho việc kiểm thử hành vi của dự án phần mềm đều nằm trong lớp FeatureContext.
Để Behat có thể sử dụng đƣợc lớp ngữ cảnh, có ba nguyên tắc cơ bản sau: 1. Lớp ngữ cảnh nên cài đặt theo lớp ContextInterface hoặc kế thừa lớp BehatContext trong thƣ mục Behat\Behat\Context\
2.Lớp ngữ cảnh thƣờng đƣợc đặt tên là FeatureContext, đúng theo quy ƣớc của Behat.
3. Khi làm việc Behat sẽ tự động tìm và gọi các tập tin .php trong thƣ mục features/bootstrap, do đó lớp ngữ cảnh nên đƣợc lƣu trong thƣ mục này.
Lớp ngữ cảnh thƣờng đƣợc Behat tự động sinh ra khi ngƣời lập trình gọi lệnh lệnh behat -- init, lớp này chứa trong tập tin FeatureContext.php và khi thực hiện chức năng kiểm thử, theo mặc định Behat sẽ gọi tập tin này. Tuy nhiên
ngƣời phát triển có thể đặt tên tập tin hoặc chọn đƣờng dẫn lƣu lớp ngữ cảnh ở một nơi khác, lúc đó lập trình viên cần thay đổi một số tham số trong tập tin cấu hình behat.yml (mục3.5).
3.3. Phát triển ứng dụng Web với Mink
Ngƣời dùng làm việc với ứng dụng web thông qua trình duyệt web. Trình duyệt chính là cửa sổ để ngƣời sử dụng tƣơng tác với ứng dụng và các ngƣời dùng khác. Để kiểm thử ứng dụng web, đặc biệt là kiểm thử chấp nhận tƣ̣ đô ̣ng cần có các biê ̣n pháp mô phỏng tƣơng tác giữa trình duyệt và ứng dụng web. Có khá nhiều trình duyệt mô phỏng, mỗi loại hoạt động theo cơ chế khác nhau. Tuy nhiên, có hai nhóm trình duyệt mô phỏng chính là:
Trình duyệt giả định headless. Bộ điều khiển trình duyệt.
Loại trình duyệt đầu tiên khá đơn giản, và thƣờng chỉ là các cài đặt để thực hiện HTTP đơn thuần, chúng gửi một yêu cầu HTTP và nhận nội dung phản hồi. Trình duyệt loại này thƣờng là các đoạn mã chƣơng trình đƣợc thực hiện thông qua việc gọi các lệnh tƣ̀máy chủ (server), chúng không có giao diện đồ họa vì thế tốc độ thực hiện nhanh. Tuy nhiên, trình duyệt headless thƣờng không hỗ trợ JS, Ajax, CSS nên không thể sử dụng để kiểm thử giao diện của ứng dụng web.
Loại thứ hai là các bộ điều khiển trình duyệt nhằm mục đích điều khiển các trình duyệt thực sự. Các bộ điều khiển trình duyệt mô phỏng tƣơng tác của ngƣời sử dụng trên trình duyệt và có thể khôi phục thông tin từ trình duyệt trang hiện thời. Loại này hỗ trợ JS/Ajax, tuy nhiên chúng yêu cầu phải cài đặt các trình duyệt thực sƣ̣ và thêm một số cấu hình vì thế tốc độ của nó chậm hơn loại trình duyệt mô phỏng đầu tiên.
Khi kiểm thử một ứng dụng, tùy thuô ̣c vào mục đích và nội dung kiểm thử để chọn loại trình duyệt mô phỏng phù hợp . Thông thƣờng để kiểm thử ứng dụng web mô ̣t cách tro ̣n ve ̣n cần phải sử dụng cả hai lo ại trình duyệt mô phỏng nêu trên.
Mink là mô ̣t nền tảng mã nguồn mở , đƣợc viết bằng PHP 5.3 hỗ trợ cả hai loại trình duyệt trên. Mink đƣợc sƣ̉ du ̣ng rô ̣ng rãi trong kiểm thƣ̉ chấp nhâ ̣n ƣ́ng dụng Web . Mink loại bỏ các API (Application Programming Interface – Giao diê ̣n chƣơng trình ƣ́ng du ̣ng ) khác nhau giữa các trình duyệt trình duyệt mô phỏng khác nhau, cung cấp cách đơn giản nhất để kiểm soát các trình duyệt, các trang và các thành phần của trang.Mink cũng cung cấp các API phù hợp cho các loại trình duyệt khác nhau hay viết bằng ngôn ngữ khác nhau thông qua các bô ̣
điều khiển. Thành phần điều khiển đƣợc viết tro ng lớp Driver \DriverInterface, lớp này cung cấp các phƣơng thức làm cầu nối giữa Mink và trình duyệt thực sự.
3.4. Lớp MinkContext
Kiểm thƣ̉ tƣ̣ đô ̣ng các ƣ́ng du ̣ng web đòi hỏi phải làm viê ̣c với trình duyê ̣t mô phỏng để chúng có thể kiểm s oát các thao tác ngƣời dùng thực hiện trên trang web nhƣ thao tác chuyển trang , tải trang, hay các thao tác điều khiển các thành phần trên trang . Để các hoa ̣t đô ̣ng này đƣợc thƣ̣c hiê ̣n tƣ̣ đô ̣ng cần có cơ chế để trình duyê ̣t mô p hỏng đọc, hiểu tài liê ̣u yêu cầu và liên kết chúng với các phƣơng thƣ́c kiểm thƣ̉ tƣơng ƣ́ng . Mink cung cấp lớp ngƣ̃ cảnh MinkContext để cài đặt các định nghĩa bƣớc theo dạng các biểu thức chính quy và phƣơng thức kiểm thƣ̉ tƣơng ƣ́ng.
MinkContext cung cấp rất nhiều phƣơng thƣ́c phù hợp với hoa ̣t đô ̣ng của ứng dụng web , cũng giống nhƣ các lớp ngữ cảnh mỗi phƣơng thức của
MinkContext ƣ́ng với mô ̣t biểu thƣ́c chính quy để biểu diễn chúng ƣ́ng các tiêu chí kiểm thƣ̉ chấp nhâ ̣n. Ví dụ:
# features/search.feature Feature: Search
In order to see a word definition As a website user
I need to be able to search for a word
Scenario: Searching for a page that does exist Given I am on "/wiki/Main_Page"
When I fill in "search" with "Behavior Driven Development" And I press "searchButton"
Then I should see "agile software development" Scenario: Searching for a page that does NOT exist Given I am on "/wiki/Main_Page"
When I fill in "search" with "Glory Driven Development" And I press "searchButton"
Then I should see "Search results"
Để kiểm thƣ̉ tƣ̣ đô ̣ng cần phải có trình duyê ̣t mô phỏng nhằm thƣ̣c hiê ̣n các thao tác nhƣ tải trang , nhâ ̣p dƣ̃ liê ̣u , gƣ̉i dƣ̃ liê ̣u của form lên máy chủ . Mink cung cấp các điều khiển để có thể đo ̣c và thƣ̣c hiê ̣n tƣ̣ đô ̣ng các thao tác đó , và trả về kết quả để Behat báo cáo kết quả kiểm thử các tính năng.
MinkContext cung cấp các đi ̣nh nghĩa bƣớ c tƣơng ƣ́ng với các tiêu chí kiểm thƣ̉ chấp nhâ ̣n trong tài liê ̣u đă ̣c tả . Mỗi đi ̣nh nghĩa bƣớc chƣ́a mô ̣t biểu thƣ́c chính quy đƣợc viết dƣới da ̣ng ngôn ngƣ̃ tƣ̣ nhiên dễ sƣ̉ du ̣ng . Các bảng dƣới đây cung cấp mô ̣t số biểu thƣ́c chính quy phổ biến của MinkContext.
Để mô tả việc gọi trang hay gửi các yêu cầu, MinkContext cung cấp các dạng biểu thức nhƣ mô tả ở Bảng 3-2.
Biểu thƣ́c chính quy Mô tả
Given /^I am on "(?P<page>[^"]+)"$/ Mở mô ̣t trang cu ̣ thể When /^I go to "(?P<page>[^"]+)"$/ Mở mô ̣t trang cu ̣ thể pageWhen /^I reload the page$/ Tải lại trang
When /^I move backward one page$/ Về trang trƣớc When /^I move forward one page$/ Đến trang tiếp theo When /^I press
"(?P<button>(?:[^"]|")*)"$/
Nhấn mô ̣t nút, tham số button ở đây có thể là id|name|title|alt|value của button
When /^I follow "(?P<link>(?:[^"]|")*)"$/ Click vào mô ̣t liên kết cu ̣ thể, tham số link ở đây có thể là
id|title|alt|text của liên kết
Bảng 3-2 MinkContext với các đi ̣nh nghĩa bƣớc để ta ̣o yêu cầu
Để thực hiện các thao tác với dữ liệu trên Form nhập, MinkContext cung cấp các dạng biểu thức nhƣ mô tả trong Bảng 3-3.
Biểu thƣ́c chính quy Mô tả
When /^I fill in "(?P<field>(?:[^"]|")*)" with "(?P<value>(?:[^"]|")*)"$/
Nhâ ̣p giá tri ̣ cho mô ̣t ô nhâ ̣p với Field có thể là id|label|name của input
When /^I fill in "(?P<value>(?:[^"]|")*)" for "(?P<field>(?:[^"]|")*)"$/
Nhâ ̣p giá tri ̣ cho mô ̣t ô nhâ ̣p với Field có thể là id|label|name của input
When /^I fill in the following:$/ Nhâ ̣p các giá tri ̣ cho trong bảng When /^I select "(?P<option>(?:[^"]|")*)"
from "(?P<select>(?:[^"]|")*)"$/
Chọn giá trị trong ô nhập select – option voiws <select> là
id||name|label|value của ô nhâ ̣p When /^I check
"(?P<option>(?:[^"]|")*)"$/
Check cho ̣n ô check-box với <option> là id||name|label|value của ô nhập
When /^I uncheck
"(?P<option>(?:[^"]|")*)"$/ Bỏ chọn ô check-box với <option> là id||name|label|value của ô nhâ ̣p When /^I attach the file "(?P<path>[^"]*)"
to "(? P<field>(?:[^"]|")*)"$/
Đính kèm file vào ô nhâ ̣p với <field> là id||name|label|value của ô nhâ ̣p
Bảng 3-3 MinkContext các đi ̣nh nghĩa với bƣớc tƣơng tác Form
Ngoài ra để phù hợp với kịch bản dàn ý của Gherkin, MinkContext cũng hỗ trợ các loại bƣớc với dữ liệu kiểu phức hợp. Có hai loại tham số phức hợp là tham số dạng bảng và tham số da ̣ng pystring.
Chẳng hạn để mô tả các bƣớc gần giống nhau, chỉ khác nhau về tham số ta có thể sử dụng kiểu dữ liệu bảng theo cấu trúc sau:
When I fill in the following: | agr1 | value 1 |
| agr2 | value 2 | | … | …. |
Ví dụ để mô tả các bƣớc
When I fill in “email” with “sample@gmail.com” And I fill in “message” with “Hello there”
Ta có thể viết lại nhƣ sau:
When I fill in the following: | email |sample@gmail.com | | message | Hello there |
MinkContext cũng cung cấp các biểu thức chính quy để kiểm tra các thành phần của DOM nhƣ mô tả ở Bảng 3-4.
Biểu thƣ́c chính quy Mô tả
Then /^I should see
"(?P<text>(?:[^"]|")*)" in the "(?P<element>[^"]*)" element$/
Kiểm tra phần tử <element> chứa <text> cụ thể.
Then /^the "(?P<element>[^"]*)" element should contains
"(?P<value>(?:[^"]|")*)"$/
Kiểm tra phần tử <element chứa nội dung HTML cụ thể.
Then /^I should see an?
"(?P<element>[^"]*)" element$/
Kiểm tra tồn tại phần tử <element> trên trang .
Then /^I should not see an? "(?P<element>[^"]*)" element$/
Kiểm tra không tồn tại phần tử <element> trên trang .
Then /^the "(?P<field>(?:[^"]|")*)" field should contain
"(?P<value>(?:[^"]|")*)"$/
Kiểm tra một phần tử của form chứa giá trị cụ thể. Phần tử của form đƣợc xác định bởi id|label|value|name Then /^the "(?P<field>(?:[^"]|")*)" field
should not contain
"(?P<value>(?:[^"]|")*)"$/
Kiểm tra một phần tử của form không chứa giá trị cụ thể. Phần tử của form đƣợc xác định bởi id|label|value|name Then /^the "(?P<checkbox>(?:[^"]|")*)"
checkbox should be checked$/
Kiểm tra trạng thái đƣợc check của một checkbox
Then /^the "(?P<checkbox>(?:[^"]|")*)" checkbox should not be checked$/
Kiểm tra trạng thái không đƣợc check của một checkbox
Bảng 3-4 MinkContext định nghĩa các bƣớc cho DOM
Để kiểm tra phản hồi của trình duyệt MinkContext cung cấp các biểu thức chính quy nhƣ mô tả trong Bảng 3-5.
Biểu thƣ́c chính quy Mô tả
Then /^I should be on "(?P<page>[^"]+)"$/
Kiểm tra địa chỉ trang với giá trị cụ thể
Then /^the url should match "(?P<pattern>(?:[^"]|")*)"$/
Kiểm tra địa chỉ trang chứa thành phần <pattern>
Then /^the response status code should be (?P<code>d+)$/
Kiểm tra phản hồi của trang bằng một giá trị cụ thể.
Bảng 3-5MinkContext với các bƣớc kiểm tra hồi đáp trang
MinkContext giúp viê ̣c viết kiểm thƣ̉ ƣ́ng du ̣ng web đƣợc thƣ̣c hiê ̣n dễ dàng hơn . Ngƣời sƣ̉ du ̣ng chỉ cần sƣ̉ du ̣ng mô ̣t ngôn ngƣ̃ mô hình miền ƣ́ng dụng để mô tả hành vi của hệ thống bằng các câu lệnh tƣơng ứng với biểu thức chính quy do MinkContext cung cấp . Đồng thời lớp ngƣ̃ cảnh FeatureContext chƣ́a các đi ̣nh nghĩa kiểm thƣ̉ bƣớc sẽ kế thƣ̀a MinkContext thay cho
BehatContext.
3.5. Cấu hình Behat với behat.yml
Khi sử dụng Behat, với các ứng dụng phức tạp cần cấu hình cho bộ tính năng, Behat sử dụng cấu hình YAML để cấu hình file và profile. Tất cả cấu hình đƣợc đi ̣nh bên trong m ột tập tin cấu hình có định dạng .yml, mặc định Behat sẽ đọc tập tin behat.yml hoặc config/behat.yml để tải các cấu hình cho ứng dụng sƣ̉ dụng Behat.
Một tập tin cấu hình chứa các cấu hình về các thành phần mở rộng, đi ̣nh dạng kết quả trả về , đƣờng dẫn trang web cần kiểm thử, … .Nhìn chung tập tin cấu hình có định dạng nhƣ Hình 3-5. # behat.yml default: paths: features: 'features' bootstrap: 'features/bootstrap' context: parameters: default_browser: 'goutte' ansi: ~
test_param:'abc' test_pass: 'xyz' extensions: Behat\MinkExtension\Extension: goutte: guzzle_parameters: ssl.certificate_authority: system curl.options: 64: false # CURLOPT_SSL_VERIFYPEER 172: false # CURLOPT_CERTINFO selenium2: ~ Test\TestExtension\Extension: imports: - behat.local.yml […]
Hình 3-5 Cấu hình behat.yml
Trong tâ ̣p tin cấu hình behat .yml, có nhiều khối cấu hình khách nhau . Các cấu hình cơ bản nhƣ sau:
Paths: Khối cấu hình đầu tiên là paths, các tham số của khối cấu hình này sẽ chỉ ra đi ̣a chỉ thƣ mu ̣c chƣ́a các tính năng features và các tâ ̣p tin bootstrap để Behat làm việc. # behat.yml default: paths: features: features bootstrap: %behat.paths.features%/bootstrap
Tham số features: chỉ ra đƣờng dẫn lƣu trƣ̃ các đ ịnh nghĩa tính năng *.feature, Behat tƣ̣ đô ̣ng đ ọc tất cả các tập tin có phần mở rộng .feature ở trong thƣ mục này để kiểm thử hệ thống.
Tham số bootstrap xác định thƣ mục Behat sẽ tự động tải các tập tin có phần mở rộng .php
Filters: Khối cấu hình filters xác định tính năng lọc qua các định danh hoặc tag để thực hiện các tính năng. Khi gă ̣p khối cấu hình này, Behat sẽ chỉ đo ̣c và thực hiện những tính năng mà các giá trị các tham số của khối này giới hạn.
# behat.yml default: filters: tags: "@wip"