最新服务器上的版本,以后用这个
wangzhenxin
2023-11-19 bc164b8bdbfbdf1d8229a5ced6b08d7cb8db7361
commit | author | age
2207d6 1 # Acceptance Testing
W 2
3 Acceptance testing can be performed by a non-technical person. That person can be your tester, manager or even client.
4 If you are developing a web-application (and you probably are) the tester needs nothing more than a web browser
5 to check that your site works correctly. You can reproduce an acceptance tester's actions in scenarios
6 and run them automatically. Codeception keeps tests clean and simple
7 as if they were recorded from the words of an actual acceptance tester.
8
9 It makes no difference what (if any) CMS or framework is used on the site. You can even test sites created with different
10 languages, like Java, .NET, etc. It's always a good idea to add tests to your website.
11 At least you will be sure that site features work after the latest changes were made.
12
13 ## Sample Scenario
14
15 Let's say the first test you would want to run, would be signing in.
16 In order to write such a test, we still require basic knowledge of PHP and HTML:
17
18 ```php
19 <?php
20 $I->amOnPage('/login');
21 $I->fillField('username', 'davert');
22 $I->fillField('password', 'qwerty');
23 $I->click('LOGIN');
24 $I->see('Welcome, Davert!');
25 ```
26
27 **This scenario can be performed either by PhpBrowser or by a "real" browser through Selenium WebDriver**.
28
29 | | PhpBrowser | WebDriver |
30 | --- | --- | --- |
31 | Browser Engine | Guzzle + Symfony BrowserKit | Chrome or Firefox |
32 | JavaScript | No | Yes |
33 | `see`/`seeElement` checks if… | …text is present in the HTML source | …text is actually visible to the user |
34 | Read HTTP response headers | Yes | No |
35 | System requirements | PHP with [cURL extension](http://php.net/manual/book.curl.php) | Selenium Standalone Server, Chrome or Firefox |
36 | Speed | Fast | Slow |
37
38 We will start writing our first acceptance tests with PhpBrowser.
39
40 ## PhpBrowser
41
42 This is the fastest way to run acceptance tests since it doesn't require running an actual browser.
43 We use a PHP web scraper, which acts like a browser: It sends a request, then receives and parses the response.
44 Codeception uses [Guzzle](http://guzzlephp.org) and [Symfony BrowserKit](http://symfony.com/doc/current/components/browser_kit.html) to interact with HTML web pages.
45
46 Common PhpBrowser drawbacks:
47
48 * You can only click on links with valid URLs or form submit buttons
49 * You can't fill in fields that are not inside a form
50
51 We need to specify the `url` parameter in the acceptance suite config:
52
53 ```yaml
54 # acceptance.suite.yml
55 actor: AcceptanceTester
56 modules:
57     enabled:
58         - PhpBrowser:
59             url: http://www.example.com/
60         - \Helper\Acceptance
61 ```
62
63 We should start by creating a test with the next command:
64
65 ```
66 php vendor/bin/codecept g:cest acceptance Signin
67 ```
68
69 It will be placed into `tests/acceptance` directory.
70
71 ```php
72 <?php
73 class SigninCest
74 {
75     public function tryToTest(AcceptanceTester $I)
76     {
77         $I->wantTo('test my page');
78     }
79 }
80 ```
81
82 The `$I` object is used to write all interactions.
83 The methods of the `$I` object are taken from the [PhpBrowser Module](http://codeception.com/docs/modules/PhpBrowser). We will briefly describe them here:
84
85 ```php
86 <?php
87 $I->amOnPage('/login');
88 ```
89
90 We will assume that all actions starting with `am` and `have` describe the initial environment.
91 The `amOnPage` action sets the starting point of a test to the `/login` page.
92
93 With the `PhpBrowser` you can click the links and fill in the forms. That will probably be the majority of your actions.
94
95 #### Click
96
97 Emulates a click on valid anchors. The URL referenced in the `href` attribute will be opened.
98 As a parameter, you can specify the link name or a valid CSS or XPath selector.
99
100 ```php
101 <?php
102 $I->click('Log in');
103 // CSS selector applied
104 $I->click('#login a');
105 // XPath
106 $I->click('//a[@id=login]');
107 // Using context as second argument
108 $I->click('Login', '.nav');
109 ```
110
111 Codeception tries to locate an element by its text, name, CSS or XPath.
112 You can specify the locator type manually by passing an array as a parameter. We call this a **strict locator**.
113 Available strict locator types are:
114
115 * id
116 * name
117 * css
118 * xpath
119 * link
120 * class
121
122 ```php
123 <?php
124 // By specifying locator type
125 $I->click(['link' => 'Login']);
126 $I->click(['class' => 'btn']);
127 ```
128
129 There is a special class [`Codeception\Util\Locator`](http://codeception.com/docs/reference/Locator)
130 which may help you to generate complex XPath locators.
131 For instance, it can easily allow you to click an element on the last row of a table:
132
133 ```php
134 $I->click('Edit' , \Codeception\Util\Locator::elementAt('//table/tr', -1));
135 ```
136
137 #### Forms
138
139 Clicking links is probably not what takes the most time during the testing of a website.
140 The most routine waste of time goes into the testing of forms. Codeception provides several ways of testing forms.
141
142 Let's submit this sample form inside the Codeception test:
143
144 ```html
145 <form method="post" action="/update" id="update_form">
146      <label for="user_name">Name</label>
147      <input type="text" name="user[name]" id="user_name" />
148      <label for="user_email">Email</label>
149      <input type="text" name="user[email]" id="user_email" />
150      <label for="user_gender">Gender</label>
151      <select id="user_gender" name="user[gender]">
152           <option value="m">Male</option>
153           <option value="f">Female</option>
154      </select>
155      <input type="submit" name="submitButton" value="Update" />
156 </form>
157 ```
158
159 From a user's perspective, a form consists of fields which should be filled in, and then a submit button clicked:
160
161 ```php
162 <?php
163 // we are using label to match user_name field
164 $I->fillField('Name', 'Miles');
165 // we can use input name or id
166 $I->fillField('user[email]','miles@davis.com');
167 $I->selectOption('Gender','Male');
168 $I->click('Update');
169 ```
170
171 To match fields by their labels, you should write a `for` attribute in the `label` tag.
172
173 From the developer's perspective, submitting a form is just sending a valid POST request to the server.
174 Sometimes it's easier to fill in all of the fields at once and send the form without clicking a 'Submit' button.
175 A similar scenario can be rewritten with only one command:
176
177 ```php
178 <?php
179 $I->submitForm('#update_form', array('user' => array(
180      'name' => 'Miles',
181      'email' => 'Davis',
182      'gender' => 'm'
183 )));
184 ```
185
186 The `submitForm` is not emulating a user's actions, but it's quite useful
187 in situations when the form is not formatted properly, for example, to discover that labels aren't set
188 or that fields have unclean names or badly written IDs, or the form is sent by a JavaScript call.
189
190 By default, `submitForm` doesn't send values for buttons.  The last parameter allows specifying
191 what button values should be sent, or button values can be explicitly specified in the second parameter:
192
193 ```php
194 <?php
195 $I->submitForm('#update_form', array('user' => array(
196      'name' => 'Miles',
197      'email' => 'Davis',
198      'gender' => 'm'
199 )), 'submitButton');
200 // this would have the same effect, but the value has to be explicitly specified
201 $I->submitForm('#update_form', array('user' => array(
202      'name' => 'Miles',
203      'email' => 'Davis',
204      'gender' => 'm',
205      'submitButton' => 'Update'
206 )));
207 ```
208
209 ##### Hiding Sensitive Data
210
211 If you need to fill in sensitive data (like passwords) and hide it in logs, 
212 you can pass instance `\Codeception\Step\Argument\PasswordArgument` with the data which needs to be hidden.
213
214 ```php
215 <?php
216 use \Codeception\Step\Argument\PasswordArgument;
217
218 $I->amOnPage('/form/password_argument');
219 $I->fillField('password', new PasswordArgument('thisissecret'));
220 ```  
221
222 `thisissecret` will be filled into a form but it won't be shown in output and logs.
223
224 #### Assertions
225
226 In the `PhpBrowser` you can test the page contents.
227 In most cases, you just need to check that the required text or element is on the page.
228
229 The most useful method for this is `see()`:
230
231 ```php
232 <?php
233 // We check that 'Thank you, Miles' is on the page.
234 $I->see('Thank you, Miles');
235 // We check that 'Thank you, Miles' is inside an element with 'notice' class.
236 $I->see('Thank you, Miles', '.notice');
237 // Or using XPath locators
238 $I->see('Thank you, Miles', "//table/tr[2]");
239 // We check this message is *not* on the page.
240 $I->dontSee('Form is filled incorrectly');
241 ```
242
243 You can check that a specific HTML element exists (or doesn't) on a page:
244
245 ```php
246 <?php
247 $I->seeElement('.notice');
248 $I->dontSeeElement('.error');
249 ```
250
251 We also have other useful commands to perform checks. Please note that they all start with the `see` prefix:
252
253 ```php
254 <?php
255 $I->seeInCurrentUrl('/user/miles');
256 $I->seeCheckboxIsChecked('#agree');
257 $I->seeInField('user[name]', 'Miles');
258 $I->seeLink('Login');
259 ```
260
261 #### Conditional Assertions
262
263 Usually, as soon as any assertion fails, further assertions of this test will be skipped.
264 Sometimes you don't want this - maybe you have a long-running test and you want it to run to the end.
265 In this case, you can use conditional assertions.
266 Each `see` method has a corresponding `canSee` method, and `dontSee` has a `cantSee` method:
267
268 ```php
269 <?php
270 $I->canSeeInCurrentUrl('/user/miles');
271 $I->canSeeCheckboxIsChecked('#agree');
272 $I->cantSeeInField('user[name]', 'Miles');
273 ```
274
275 Each failed assertion will be shown in the test results, but it won't stop the test.
276
277 #### Comments
278
279 Within a long scenario, you should describe what actions you are going to perform and what results should be achieved.
280 Comment methods like `amGoingTo`, `expect`, `expectTo` help you in making tests more descriptive:
281
282 ```php
283 <?php
284 $I->amGoingTo('submit user form with invalid values');
285 $I->fillField('user[email]', 'miles');
286 $I->click('Update');
287 $I->expect('the form is not submitted');
288 $I->see('Form is filled incorrectly');
289 ```
290
291 #### Grabbers
292
293 These commands retrieve data that can be used in the test. Imagine your site generates a password for every user
294 and you want to check that the user can log into the site using this password:
295
296 ```php
297 <?php
298 $I->fillField('email', 'miles@davis.com');
299 $I->click('Generate Password');
300 $password = $I->grabTextFrom('#password');
301 $I->click('Login');
302 $I->fillField('email', 'miles@davis.com');
303 $I->fillField('password', $password);
304 $I->click('Log in!');
305 ```
306
307 Grabbers allow you to get a single value from the current page with commands:
308
309 ```php
310 <?php
311 $token = $I->grabTextFrom('.token');
312 $password = $I->grabTextFrom("descendant::input/descendant::*[@id = 'password']");
313 $api_key = $I->grabValueFrom('input[name=api]');
314 ```
315
316 #### Cookies, URLs, Title, etc
317
318 Actions for cookies:
319
320 ```php
321 <?php
322 $I->setCookie('auth', '123345');
323 $I->grabCookie('auth');
324 $I->seeCookie('auth');
325 ```
326
327 Actions for checking the page title:
328
329 ```php
330 <?php
331 $I->seeInTitle('Login');
332 $I->dontSeeInTitle('Register');
333 ```
334
335 Actions for URLs:
336
337 ```php
338 <?php
339 $I->seeCurrentUrlEquals('/login');
340 $I->seeCurrentUrlMatches('~^/users/(\d+)~');
341 $I->seeInCurrentUrl('user/1');
342 $user_id = $I->grabFromCurrentUrl('~^/user/(\d+)/~');
343 ```
344
345 ## WebDriver
346
347 A nice feature of Codeception is that most scenarios are similar, no matter of how they are executed.
348 `PhpBrowser` was emulating browser requests but how to execute such test in a real browser like Chrome or Firefox?
349 Selenium WebDriver can drive them so in our acceptance tests we can automate scenarios we used to test manually.
350 In such tests, we should concentrate more on **testing the UI** than on testing functionality.
351
352 "[WebDriver](https://www.w3.org/TR/webdriver/)" is the name of a protocol (specified by W3C)
353 to drive browsers automatically. This specification is implemented for all modern desktop and mobile browsers.
354 Codeception uses [facebook/php-webdriver](https://github.com/facebook/php-webdriver) library from Facebook as PHP implementation of WebDriver protocol.
355
356 To control the browsers you need to use a program or a service to start/stop browser sessions.
357 In the next section, we will overview the most popular solutions.
358
359 ### Local Setup
360
361 #### Selenium Server
362
363 [Selenium Server](http://www.seleniumhq.org/) is a de-facto standard for automated web and mobile testing.
364 It is a server that can launch and drive different browsers locally or remotely.
365 WebDriver protocol was initially created by Selenium before becoming a W3C standard.
366 This makes Selenium server the most stable complete implementation of WebDriver for today.
367 Selenium Server is also recommended by Codeception team.
368
369 To control browsers Selenium Server uses official tools maintained by browser vendors, like [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver) for Chrome or [GeckoDriver](https://github.com/mozilla/geckodriver) for Firefox.
370 This makes Selenium quite heavy to install, as it requires Java, browsers, Chrome or GeckoDriver and GUI (display server) to run browsers in.
371
372 * Follow [Installation Instructions](http://codeception.com/docs/modules/WebDriver#Selenium)
373 * Enable [RunProcess](http://codeception.com/extensions#RunProcess) extension to start/stop Selenium automatically *(optional)*.
374
375 #### PhantomJS
376
377 PhantomJS is a customized WebKit-based [headless browser](https://en.wikipedia.org/wiki/Headless_browser)
378 built for programmatic usage only. It doesn't display a browser window and doesn't require GUI (display server) to be installed.
379 This makes PhantomJS highly popular for Continuous Integration systems.
380 PhantomJS needs only one binary with no extra dependencies which make it the simplest WebDriver tool to install.
381
382 However, it should be noted that PhantomJS is not a real browser, so the behavior and output in real browsers may differ from PhantomJS.
383 And the most important: **PhantomJS is not maintained** anymore. So use it at your own risk.
384
385 * Follow [Installation Instructions](http://codeception.com/docs/modules/WebDriver#PhantomJS)
386 * Enable [RunProcess](http://codeception.com/extensions#RunProcess) extension to start/stop PhantomJS automatically *(optional)*.
387
388 #### ChromeDriver
389
390 ChromeDriver was created by Google to control Chrome and Chromium browsers programmatically.
391 It can be paired with [Selenium Server](http://codeception.com/docs/03-AcceptanceTests#Selenium-Server) or used as a standalone tool to drive Chrome browser.
392 It is simpler to set up than Selenium Server, however, it has limited support for WebDriver protocol.
393
394 * Follow [Installation Instructions](http://codeception.com/docs/modules/WebDriver#ChromeDriver)
395 * Enable [RunProcess](http://codeception.com/extensions#RunProcess) extension to start/stop ChromeDriver automatically *(optional)*.
396
397 ### Configuration
398
399 To execute a test in a browser we need to change the suite configuration to use **WebDriver** instead of `PhpBrowser`.
400
401 Modify your `acceptance.suite.yml` file:
402
403 ```yaml
404 actor: AcceptanceTester
405 modules:
406     enabled:
407         - WebDriver:
408             url: {{your site URL}}
409             browser: chrome
410         - \Helper\Acceptance
411 ```
412
413 See [WebDriver Module](http://codeception.com/docs/modules/WebDriver) for details.
414
415 Please note that actions executed in a browser will behave differently. For instance, `seeElement` won't just check that the element exists on a page,
416 but it will also check that element is actually visible to the user:
417
418 ```php
419 <?php
420 $I->seeElement('#modal');
421 ```
422
423 While WebDriver duplicates the functionality of PhpBrowser, it has its limitations: It can't check headers since browsers don't provide APIs for that.
424 WebDriver also adds browser-specific functionality:
425
426 #### Wait
427
428 While testing web application, you may need to wait for JavaScript events to occur. Due to its asynchronous nature,
429 complex JavaScript interactions are hard to test. That's why you may need to use waiters, actions with `wait` prefix.
430 They can be used to specify what event you expect to occur on a page, before continuing the test.
431
432 For example:
433
434 ```php
435 <?php
436 $I->waitForElement('#agree_button', 30); // secs
437 $I->click('#agree_button');
438 ```
439
440 In this case, we are waiting for the 'agree' button to appear and then click it. If it didn't appear after 30 seconds,
441 the test will fail. There are other `wait` methods you may use, like [waitForText](http://codeception.com/docs/modules/WebDriver#waitForText),
442 [waitForElementVisible](http://codeception.com/docs/modules/WebDriver#waitForElementVisible) and others.
443
444 If you don't know what exact element you need to wait for, you can simply pause execution with using `$I->wait()`
445
446 ```php
447 <?php
448 $I->wait(3); // wait for 3 secs
449 ```
450
451 #### SmartWait
452
453 *since 2.3.4 version*
454
455 It is possible to wait for elements pragmatically.
456 If a test uses element which is not on a page yet, Codeception will wait for few extra seconds before failing.
457 This feature is based on [Implicit Wait](http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp#implicit-waits) of Selenium.
458 Codeception enables implicit wait only when searching for a specific element and disables in all other cases. Thus, the performance of a test is not affected.
459
460 SmartWait can be enabled by setting `wait` option in WebDriver config. It expects the number of seconds to wait. Example:
461
462 ```yaml
463 wait: 5
464 ```
465
466 With this config we have the following test:
467
468 ```php
469 <?php
470 // we use wait: 5 instead of
471 // $I->waitForElement(['css' => '#click-me'], 5);
472 // to wait for element on page
473 $I->click(['css' => '#click-me']);
474 ```
475
476 It is important to understand that SmartWait works only with a specific locators:
477
478 * `#locator` - CSS ID locator, works
479 * `//locator` - general XPath locator, works
480 * `['css' => 'button'']` - strict locator, works
481
482 But it won't be executed for all other locator types.
483 See the example:
484
485 ```php
486 <?php
487 $I->click('Login'); // DISABLED, not a specific locator
488 $I->fillField('user', 'davert'); // DISABLED, not a specific locator
489 $I->fillField(['name' => 'password'], '123456'); // ENABLED, strict locator
490 $I->click('#login'); // ENABLED, locator is CSS ID
491 $I->see('Hello, Davert'); // DISABLED, Not a locator
492 $I->seeElement('#userbar'); // ENABLED
493 $I->dontSeeElement('#login'); // DISABLED, can't wait for element to hide
494 $I->seeNumberOfElements(['css' => 'button.link'], 5); // DISABLED, can wait only for one element
495 ```
496
497 #### Wait and Act
498
499 To combine `waitForElement` with actions inside that element you can use the [performOn](http://codeception.com/docs/modules/WebDriver#performOn) method.
500 Let's see how you can perform some actions inside an HTML popup:
501
502 ```php
503 <?php
504 $I->performOn('.confirm', \Codeception\Util\ActionSequence::build()
505     ->see('Warning')
506     ->see('Are you sure you want to delete this?')
507     ->click('Yes')
508 );
509 ```
510 Alternatively, this can be executed using a callback, in this case the `WebDriver` instance is passed as argument
511
512 ```php
513 <?php
514 $I->performOn('.confirm', function(\Codeception\Module\WebDriver $I) {
515     $I->see('Warning');
516     $I->see('Are you sure you want to delete this?');
517     $I->click('Yes');
518 });
519 ```
520
521 For more options see [`performOn()` reference](http://codeception.com/docs/modules/WebDriver#performOn).
522
523 ### Multi Session Testing
524
525 Codeception allows you to execute actions in concurrent sessions. The most obvious case for this
526 is testing realtime messaging between users on a site. In order to do it, you will need to launch two browser windows
527 at the same time for the same test. Codeception has a very smart concept for doing this. It is called **Friends**:
528
529 ```php
530 <?php
531 $I->amOnPage('/messages');
532 $nick = $I->haveFriend('nick');
533 $nick->does(function(AcceptanceTester $I) {
534     $I->amOnPage('/messages/new');
535     $I->fillField('body', 'Hello all!');
536     $I->click('Send');
537     $I->see('Hello all!', '.message');
538 });
539 $I->wait(3);
540 $I->see('Hello all!', '.message');
541 ```
542
543 In this case, we performed, or 'did', some actions in the second window with the `does` method on a friend object.
544
545 Sometimes you may want to close a webpage before the end of the test. For such cases, you may use `leave()`.
546 You can also specify roles for a friend:
547
548 ```php
549 <?php
550 $nickAdmin = $I->haveFriend('nickAdmin', adminStep::class);
551 $nickAdmin->does(function(adminStep $I) {
552     // Admin does ...
553 });
554 $nickAdmin->leave();
555 ```
556
557 ### Cloud Testing
558
559 Some environments are hard to be reproduced manually, testing Internet Explorer 6-8 on Windows XP may be a hard thing,
560 especially if you don't have Windows XP installed. This is where Cloud Testing services come to help you.
561 Services such as [SauceLabs](https://saucelabs.com), [BrowserStack](https://www.browserstack.com/)
562 and [others](http://codeception.com/docs/modules/WebDriver#Cloud-Testing) can create virtual machines on demand
563 and set up Selenium Server and the desired browser. Tests are executed on a remote machine in a cloud,
564 to access local files cloud testing services provide a special application called **Tunnel**.
565 Tunnel operates on a secured protocol and allows browsers executed in a cloud to connect to a local web server.
566
567 Cloud Testing services work with the standard WebDriver protocol. This makes setting up cloud testing really easy.
568 You just need to set the [WebDriver configuration](http://codeception.com/docs/modules/WebDriver#Cloud-Testing) to:
569
570 * specify the host to connect to (depends on the cloud provider)
571 * authentication details (to use your account)
572 * browser
573 * OS
574
575 We recommend using [params](http://codeception.com/docs/06-ModulesAndHelpers#Dynamic-Configuration-With-Params)
576 to provide authorization credentials.
577
578 It should be mentioned that Cloud Testing services are not free. You should investigate their pricing models
579 and choose one that fits your needs. They also may work painfully slowly if ping times between the local server
580 and the cloud is too high. This may lead to random failures in acceptance tests.
581
582 ### AngularJS Testing
583
584 In the modern era of Single Page Applications, the browser replaces the server in creating the user interface.
585 Unlike traditional web applications, web pages are not reloaded on user actions.
586 All interactions with the server are done in JavaScript with XHR requests.
587 However, testing Single Page Applications can be a hard task.
588 There could be no information of the application state: e.g. has it completed rendering or not?
589 What is possible to do in this case is to use more `wait*` methods or execute JavaScript that checks the application state.
590
591 For applications built with the AngularJS v1.x framework,
592 we implemented [AngularJS module](http://codeception.com/docs/modules/AngularJS) which is based on Protractor
593 (an official tool for testing Angular apps). Under the hood, it pauses step execution
594 before the previous actions are completed and use the AngularJS API to check the application state.
595
596 The AngularJS module extends WebDriver so that all the configuration options from it are available.
597
598 ### Debugging
599
600 Codeception modules can print valuable information while running.
601 Just execute tests with the `--debug` option to see running details. For any custom output use the `codecept_debug` function:
602
603 ```php
604 <?php
605 codecept_debug($I->grabTextFrom('#name'));
606 ```
607
608 On each failure, the snapshot of the last shown page will be stored in the `tests/_output` directory.
609 PhpBrowser will store the HTML code and WebDriver will save a screenshot of the page.
610
611 Additional debugging features by Codeception:
612
613 * [pauseExecution](http://codeception.com/docs/modules/WebDriver#pauseExecution) method of WebDriver module allows pausing the test.
614 * [Recorder extension](http://codeception.com/addons#CodeceptionExtensionRecorder) allows to record tests step-by-steps and show them in slideshow
615 * [Interactive Console](http://codeception.com/docs/07-AdvancedUsage#Interactive-Console) is a REPL that allows to type and check commands for instant feedback.
616
617 ### Custom Browser Sessions
618
619 By default, WebDriver module is configured to automatically start browser before the test and stop afterward.
620 However, this can be switched off with `start: false` module configuration.
621 To start a browser you will need to write corresponding methods in Acceptance [Helper](http://codeception.com/docs/06-ModulesAndHelpers#Helpers).
622
623 WebDriver module provides advanced methods for the browser session, however, they can only be used from Helpers.
624
625 * [_initializeSession](http://codeception.com/docs/modules/WebDriver#_initializeSession) - starts a new browser session
626 * [_closeSession](http://codeception.com/docs/modules/WebDriver#_closeSession) - stops the browser session
627 * [_restart](http://codeception.com/docs/modules/WebDriver#_restart) - updates configuration and restarts browser
628 * [_capabilities](http://codeception.com/docs/modules/WebDriver#_capabilities) - set [desired capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities) programmatically.
629
630 Those methods can be used to create custom commands like `$I->startBrowser()` or used in [before/after](http://codeception.com/docs/06-ModulesAndHelpers#Hooks) hooks.
631
632 ## Conclusion
633
634 Writing acceptance tests with Codeception and PhpBrowser is a good start.
635 You can easily test your Joomla, Drupal, WordPress sites, as well as those made with frameworks.
636 Writing acceptance tests is like describing a tester's actions in PHP. They are quite readable and very easy to write.
637 If you need to access the database, you can use the [Db Module](http://codeception.com/docs/modules/Db).