Skip to content

Commit daa1118

Browse files
author
davert
committed
new ragazzos post added
1 parent d00b73e commit daa1118

File tree

1 file changed

+215
-0
lines changed

1 file changed

+215
-0
lines changed
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
---
2+
layout: post
3+
title: "Playng with Cests"
4+
date: 2013-05-11 22:03:50
5+
---
6+
7+
*This is the second blogpost from Ragazzo on using Cest format in functional tests.*
8+
9+
As you already saw it is easy to use flat Cept files in Codeception for your tests. But what if you want to test CRUD operations so a Cept can take 50-70 rows long. In this case it would not be so "easy-to-read".
10+
11+
This is where Codeception's Cests are really good to use. Cests are simple classes with no parents. You can use them like your classic PHPUnit classes. All that need to know is that each ```public``` Cest method is a separated scenario, which could be represented by a Cept file.
12+
13+
The other issue we want to solve with Cest files is **UI mapping**. It's ok to start testing with relying on button names and field labels. But the more UI elements come to page, the more complex our selectors become. There should be a way to manage those UI elements for tests. It's better not to put too much CSS/XPath code into scenario as it affetcs readbility of code and hardens its support.
14+
15+
Lets see example of testing simple Yii 1.1 application page in Cest-way with ```PhpBrowser``` module:
16+
17+
```php
18+
<?php
19+
20+
/**
21+
* IndexCest class file.
22+
* @author Ragazzo
23+
*/
24+
25+
namespace basic;
26+
27+
use Codeception\CestCase;
28+
29+
class IndexCest
30+
{
31+
32+
/**
33+
* user name text field
34+
* @type string
35+
*/
36+
public $username = '#LoginForm_username';
37+
38+
/**
39+
* user password text field
40+
* @type string
41+
*/
42+
public $password = '#LoginForm_password';
43+
44+
/**
45+
* submit button
46+
* @type string
47+
*/
48+
public $enterButton = '#login-form input[type=submit]';
49+
50+
/**
51+
*
52+
* @param \TestGuy $I
53+
* @param \Codeception\Scenario $scenario
54+
*/
55+
public function check_basic_login_logout(\TestGuy $I, $scenario)
56+
{
57+
$I->wantTo('Test index page');
58+
$I->amOnPage('/');
59+
$I->see('My Web Application','#header');
60+
$I->click('Login');
61+
$I->amGoingTo('login in the test app');
62+
$I->fillField($this->username,'demo');
63+
$I->fillField($this->password,'demo');
64+
$I->click($this->enterButton);
65+
$I->seeLink('Logout (demo)');
66+
$I->click('Logout (demo)');
67+
$I->seeLink('Login');
68+
}
69+
70+
}
71+
?>
72+
```
73+
74+
As you see, it was easy to add move out selectors into UI properties if we are inside a calss.
75+
76+
Example of how to test CRUD operations with Selenium2 module is below. Please notice that all support methods are `protected`. They are called from test methods and won't be executed as test themeselves.
77+
78+
```php
79+
<?php
80+
/**
81+
* "Users" module CrudCest class file
82+
* @author Ragazzo
83+
*/
84+
85+
class CrudCest
86+
{
87+
88+
/**
89+
* your fields definitions goes
90+
* here with UI-mappings
91+
* and other fields.
92+
*
93+
*/
94+
95+
private $_userId;
96+
97+
/**
98+
* new user created attributes
99+
*/
100+
private $_newAttrs = array(
101+
'name' => 'Ragazzo',
102+
'email' => 'someRagazzoEmail@example.com',
103+
'skype' => 'someRagazzoSkype',
104+
);
105+
106+
/**
107+
* edited user attributes
108+
*/
109+
private $_editAttrs = array(
110+
'skype' => 'newRagazzoSkype',
111+
);
112+
113+
/**
114+
*
115+
* @param \WebGuy $I
116+
* @param \Codeception\Scenario $scenario
117+
*/
118+
public function test_basic_users_module_crud(\WebGuy $I, $scenario)
119+
{
120+
$I->wantTo('create user and test basic crud in "Users" module');
121+
$I->am('system root user');
122+
$I->loginIntoTheSystem('somelogin','somepassword',$I);
123+
$this->create_new_user($I, $scenario);
124+
$this->update_created_user($I, $scenario);
125+
$this->delete_created_user($I, $scenario);
126+
}
127+
128+
/**
129+
*
130+
* @param \WebGuy $I
131+
* @param \Codeception\Scenario $scenario
132+
*/
133+
protected function create_new_user($I, $scenario)
134+
{
135+
$I->amGoingTo('create new user');
136+
$I->amOnPage('/users');
137+
138+
$I->see('Users','.breadcrumbs')
139+
$I->see('Create','.btn');
140+
141+
$I->click('Create','.btn');
142+
$I->seeInCurrentUrl('users/create');
143+
$I->see('Create','.breadcrumbs');
144+
145+
$I->amGoingTo('submit form without required fields');
146+
$I->click($this->saveButton);
147+
148+
$I->expectTo('see required validation errors');
149+
$I->see('Name field can not be empty');
150+
151+
$I->amGoingTo('submit correctly filled form');
152+
$I->fillField($this->name, $this->_newAttrs['name']);
153+
$I->fillField($this->email, $this->_newAttrs['email']);
154+
$I->fillField($this->skype, $this->_newAttrs['skype']);
155+
$I->click($this->saveButton);
156+
157+
$I->expectTo('see correctly saved user info');
158+
$I->seeInCurrenturl('users/view');
159+
$I->see('View','.breadcrumbs');
160+
$I->see('Delete','.btn');
161+
$I->see('Edit','.btn');
162+
$I->seeElement('.detail-view');
163+
$I->see($this->_newAttrs['name'],'.detail-view');
164+
$I->see($this->_newAttrs['email'],'.detail-view');
165+
$I->see($this->_newAttrs['skype'],'.detail-view');
166+
167+
$this->_userId = $I->grabFromCurrentUri('~/id/(\d+)/~');
168+
}
169+
170+
/**
171+
*
172+
* @param \WebGuy $I
173+
* @param \Codeception\Scenario $scenario
174+
*/
175+
protected function update_created_user($I, $scenario)
176+
{
177+
$I->amGoingTo('change created user attributes');
178+
$I->amOnPage($this->editUrl.$this->_userId);
179+
$I->fillField($this->skype, $this->_editAttrs['skype']);
180+
$I->click($this->saveButton);
181+
182+
$I->expectTo('see that attributes has changed');
183+
$I->seeInField($this->skype,$this->_editAttrs['skype']);
184+
}
185+
186+
/**
187+
*
188+
* @param \WebGuy $I
189+
* @param \Codeception\Scenario $scenario
190+
*/
191+
protected function delete_created_user($I, $scenario)
192+
{
193+
$I->amOnPage('/users');
194+
$I->see($this->_newAttrs['name'],'#users-grid');
195+
$I->click($this->_newAttrs['name'],'#users-grid');
196+
$I->see('Delete','.btn');
197+
$I->click('Delete','.btn');
198+
$I->seeInCurrentUrl('/users');
199+
$I->dontSee($this->_newAttrs['name'],'#users-grid');
200+
}
201+
202+
}
203+
?>
204+
```
205+
In this way you can use Cests classes for some tasks where it is difficult to use flat Cepts. You also can use Cests classes as PageObjects.
206+
207+
When you write tests with Codeception it is good to be verbose and use different methdos for that, so use them:
208+
- `$I->am` to say who you are and define your role;
209+
- `$I->wantTo` to say what feature you want to test;
210+
- `$I->amGoingTo` to say what you gonna do next;
211+
- `$I->expect` and `$I->expectTo` to say what do expect next to see in your test case as a user.
212+
213+
Use this commands instead of comments in your tests. They will be displayed in scenario output and will provide you with additional information on steps taken.
214+
215+
*We can say to Ragazzo for sharing his experience in using the bleeding edge feature of Cest classes. Stil it might be a point of discussion, should a CRUD be tested in one test or in four. Still in both cases Cest classes are a good places to keep everything you need to test dealing with one entity. A user, in this case.

0 commit comments

Comments
 (0)