@msvrtan
Do you test your code?
Really, you just write code and deploy it?
Writing tests takes a lot of time and resources, we don't have that luxury.
Manual testing took much more.
Who is going to pay for that?
My clients are already paying me for a good quality product.
15.000 vs 100.000 EURs
"smart people write down, stupid remember"
Users can use their email address instead of username to log in.
Users with admin privileges need to use separate login form
Could you remember all of this rules after 6 months?
Are you sure that person working on it is well aware of all the behaviours/rules?
instead of verifying old rules manually, machine validates them for you
cause i'm lazy
Scenario: Check that login works
Given I am on login page
And I fill in "username" with "joe"
And I fill in "password" with "pass123"
And I press "Login"
Then I should see "Hi Joe!"
And I should be on home page
Gherkin is a Business Readable, Domain Specific Language created specifically for behavior descriptions. It gives you the ability to remove logic details from behavior tests.
Gherkin serves as your project’s documentation as well as your project’s automated tests. Behat also has a bonus feature: It talks back to you using real, human language telling you what code you should write.
It’s the idea that you start by writing human-readable sentences that describe a feature of your application and how it should work, and only then implement this behavior in software.
Idea is to use human-readable sentences that describe a feature of your application and how it should work to verify that it works as expected after introducing changes.
{
...
"require": {
...
"behat/behat": "~3.0@dev",
"behat/mink-extension": "~2.0@dev",
"behat/mink-browserkit-driver": "~1.2@dev",
"behat/mink-selenium2-driver": "~1.2@dev",
"behat/mink": "~1.6@dev",
"behat/mink-goutte-driver": "~1.1"
},
"config": {
"bin-dir": "bin/"
}
...
}
suites:
web:
contexts: [ FeatureContext ]
filters:
tags: "~@javascript && ~@wip"
js:
contexts: [ FeatureContext ]
filters:
tags: "@javascript && ~@wip"
wip:
contexts: [ FeatureContext ]
filters:
tags: "@wip"
extensions:
Behat\MinkExtension:
base_url: http://demo.sonata-project.org/
sessions:
default:
goutte:
..
javascript:
selenium2: ~
browser_name: firefox
...
Scenario: Registration is available from homepage
Given I am on homepage
And I click "Sign Up"
Then I should see "Registration form"
And I should be on registration form
Scenario: Registration is available from homepage
Given I am on "/"
And I click "Sign Up"
Then I should see "Registration form"
And I should be on "/registration/"
Scenario: Boat page redirects from old to new url using slug
Given I am on "/product/show/product-xx"
Then url is "/product/category1/product-xx-1"
And I should see "Product XX"
/**
* Checks, that URL is equal to specified.
* @Then /^url is "(?P<url>[^"]+)"$/
*/
public function assertUrl($url)
{
$expectedUrl = $this->locatePath($url);
$actualUrl = $this->getSession()->getCurrentUrl();
if ($expectedUrl !== $actualUrl) {
$msg = sprintf('Current url is "%s", but "%s" expected.', $actualUrl, $expectedUrl);
throw new \Exception($msg);
}
}
Scenario: Check boat page redirect from old to new url using boat id
Given I am on "/product/category1/product-xx-1"
Then url is "/product/category1/brand-product-xx-1"
And I should see "Product XX"
Scenario: Boat page redirects from old to new url using slug
Given I am on "/product/show/product-xx"
Then url is "/product/category1/brand-product-xx-1"
And I should see "Product XX"
Scenario: Check boat detailview page redirect if slugs don't match
Given I am on "/product/category2/wrong-url-1"
Then url is "/product/category1/brand-product-xx-1"
And I should see "Product XX"
Scenario: Getting 404 if no boat found
Given I am on "/product/category3/brand-fake-1000000000"
Then the response status code should be 404
Scenario: Select category
Given I am on "/search/"
And I select "Category1" from "category"
And I press "Search"
Then I should see "We have found 40 products in Category1."
And url is "/search/?categories=category1"
Scenario: Search by category & price
Given I am on "/search/"
And I select "Category1" from "category"
And I fill in "price_from" with "25"
And I fill in "price_to" with "35"
And I press "Search"
Then url is "/search/?categories=category1&price_from=25&price_to=35"
And I should see "We have found 4 products."
@javascript
Scenario: Filter Example brand on category1
Given I am on "/search/?categories=category1"
And I click "Example"
Then I wait for Ajax request to process
And I should see "We have found 1 product."
And url is "/search/?categories=category1&brand=example"
Scenario: Check that new users can register
Given there is no user on site with email "email@example.com"
And I am on "/register"
And I fill in "first_name" with "Joe"
And I fill in "last_name" with "Smith"
And I fill in "user_email" with "email@example.com"
And I fill in "user_password" with "pass123"
And I check "terms"
And I press "Register"
Then url is "/"
@javascript
Scenario: Logged in user buys product using credit card
Given I am on "/some-url-product-1"
And I press "Buy It"
Then I wait for Ajax request to process
And I should be on "/cart/checkout/details"
And I should see "Product XX" on page headline
And I should see "€20"
And I press "Continue to payment plan"
Then I wait for Ajax request to process
....
Scenario: Buy something
...
Then I wait for Ajax request to process
And I should be on "/cart/checkout/payment"
And I should see "Payment details" on page headline
And I should see "€20"
And I fill in "cc_number" with "12345678901234"
And I select "02" from "cc_expiration_month"
And I select "2017" from "cc_expiration_year"
And I fill in "cc_cvx" with "123"
And I press "Complete purchase"
Then I wait for Ajax request to process
....
Scenario: Buy something
...
Then I wait for Ajax request to process
And I should be on "/cart/checkout/thanks"
And I should see "Thank you for buying XX" on page headline
/**
* @Then I wait for Ajax request to process
*/
public function iWaitForAjaxRequestToProcess()
{
//Wait for 10 seconds or until ajaxProcessFlag is equal to 1.
$this->getSession()->wait(10000, "ajaxProcessFlag==1");
}
Feature: User login
In order for users to update content
As a user
I need to log in
Feature: User login
In order for users to buy stuff
As a user
I need to log in
OR
Background:
Given I am on "/login"
And I fill in "username" with "admin"
And I fill in "password" with "admin"
And I press "Log In"
Scenario: Check that login is accessible from homepage
Given I am on "/"
...
@javascript
Scenario: Check that login works
Given I am on "/login"
...
Scenario: Check that login fails gracefully when wrong password
Given I am on "/login"
...
Some of the code examples and ideas:
https://github.com/nulldevelopmenthr/standalone-behat
twitter: @msvrtan email: miro@mirosvrtan.me