While unit tests are used to test standalone components or component groups, functional tests allow for the testing of the complete application, like black box testing. We don't know what is inside and can only provide an input and get/verify the output. In our case, the input is the actions the user carries out in a browser, such as clicking on buttons or links, loading pages, and so on, while the output is what happens in the browser.
For our example, we will create a simple "check all" widget with a single button that checks and unchecks all checkboxes on the current page.
protected/components/ECheckAllWidget.php
as follows:<?php class ECheckAllWidget extends CWidget { public $checkedTitle = 'Uncheck all'; public $uncheckedTitle = 'Check all'; public function run() { Yii::app()->clientScript->registerCoreScript('jquery'), echo CHtml::button($this->uncheckedTitle, array( 'id' => 'button-'.$this->id, 'class' => 'check-all-btn', 'onclick' => ' switch($(this).val()) { case "'.$this->checkedTitle.'": $(this).val("'.$this->uncheckedTitle.'"); $("input[type=checkbox]").attr("checked", false); break; case "'.$this->uncheckedTitle.'": $(this).val("'.$this->checkedTitle.'"); $("input[type=checkbox]").attr("checked", true); break; } ' )); } }
protected/controllers/CheckController.php
as follows:<?php class CheckController extends Controller { function actionIndex() { $this->render('index'), } }
protected/views/check/index.php
, as follows:<?php $this->widget('ECheckAllWidget')?> <?php echo CHtml::checkBox('test1', true)?> <?php echo CHtml::checkBox('test2', false)?> <?php echo CHtml::checkBox('test3', true)?> <?php echo CHtml::checkBox('test4', false)?> <?php echo CHtml::checkBox('test5', true)?> <?php echo CHtml::checkBox('test6', true)?>
Let's imagine how we would test it manually:
Now we will implement the functional test, doing exactly the same as described previously:
protected/tests/functional/CheckAllWidgetTest.php
as follows:<?php class CheckAllWidgetTest extends WebTestCase { public function testWidget() { $this->open('check/index'), $this->assertEquals("Check all", $this->getAttribute("class=check-all-btn@value")); $this->click("class=check-all-btn"); $this->assertChecked("css=input[type=checkbox]"); $this->assertEquals("Uncheck all", $this->getAttribute("class=check-all-btn@value")); $this->click("class=check-all-btn"); $this->assertNotChecked("css=input[type=checkbox]"); $this->assertEquals("Check all", $this->getAttribute("class=check-all-btn@value")); } }
cd path/to/protected/tests phpunit functional/CheckAllWidgetTest.php
You should get the following output:
onclick
handler:This means that your widget does not work as expected. In this case, the test failed on line 11
.
$this->assertEquals("Uncheck all", $this->getAttribute("class=check-all-btn@value"));
The actual value was still Check all
but the test expected Uncheck all
.
PHPUnit starts executing all the methods named like testSomething
one by one. As we have only one method, it executes testWidget
:
$this->open('check/index'),
It opens a page we created for testing:
$this->assertEquals("Check all", $this->getAttribute("class=check-all-btn@value"));
It gets button text and checks if it equals the string provided. The getAttribute
method searches for a DOM element with a class check-all-btn
and returns its value
attribute text.
$this->click("class=check-all-btn");
It clicks an element with a class check-all-btn
. That is the button.
$this->assertChecked("css=input[type=checkbox]");
The assertChecked
and assertNotChecked
methods are used to find whether a checkbox is checked. This time we use a CSS selector, input[type=checkbox]
, to get all the checkboxes.
Inside, we call methods such as getAttribute
or assertChecked
, and pass it to the Selenium server, which does the actual work and returns the result.
In order to learn more about the functional testing, you can refer to the following resources:
18.221.239.148