Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Web Services Unit Test: Difference between revisions

From MoodleDocs
(Created page with "= Delete simpletest web service unit tests With PHP Unit coming up to Moodle 2.3 we'll be removing the web service simpletest unit tests. The reasons are: * these unit tests are ...")
 
(25 intermediate revisions by 2 users not shown)
Line 1: Line 1:
= Delete simpletest web service unit tests
{{Moodle 2.3}}Since Moodle 2.3 we are using PHP Unit framework. Writing a unit test before writing an external function will end up to be very helpful. The easiest external function is not an easy task, as you can see in [[How to contribute a web service function to core]]. When writing PHPUnit tests you will:
With PHP Unit coming up to Moodle 2.3 we'll be removing the web service simpletest unit tests. The reasons are:
* discover use cases you didn't think about.
* these unit tests are only web service call tests. It would be good to have unit tests for : servers / web service call / external lib / core lib function.
* understand the feelings and the needs of the web service client developer.
* some unit tests are just one quick call. It seems sometimes obvious that some other use cases should have been tested.
* end up with a function usable by everybody, not only by your own client.
* some unit tests create and delete user/category/grouo/course/... in the database. It seems that PHP Unit could facilitate this kind of testing, not sure though...
* reach integration way faster as you joined a proof of validity
* some web service functions don't have unit test at all
* make the QA process a breeze
* it's buggy: MDL-30210


== How to run a PHPUnit test ==
you should read first the [[PHPUnit]] Moodle documentation to have a grasp of PHPUnit in Moodle.


= Add PHP Unit web service unit tests =
== How to write an external function PHPUnit test ==
I see three kind of unit test related to one web service
If it doesn't exist create a COMPONENTFOLDER/tests/externallib_test.php file.
# external function unit test: This is actually testing xxx_params too as each external funtion should call it. Here the questions is do we want to test xxx_returns at the same time?
# web service call test: I think this is required to properly test all servers against all call. here the question is to know if we want to reproduce all the same use case then for external function
# core lib function unit test: most of time these kind of unit test don't exist. Note: often the core lib function doesn't exist itself, the external function being a code logic duplication of multiple scripts.


= Web service automatic testing =
<code php>
TBD
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
/**
* COMPONENT External functions unit tests
*
* @package    core_component
* @category  external
* @copyright  20XX Your Name
* @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
 
defined('MOODLE_INTERNAL') || die();
 
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
require_once($CFG->dirroot . '/COMPONENT/externallib.php');
 
class COMPONENT_external_testcase extends externallib_advanced_testcase {
 
    /**
    * Test
    */
    public function test_FUNCTION_NAME() {
        global $USER;
 
        $this->resetAfterTest(true);
 
        // Set the required capabilities by the external function
        $contextid = context_XXXX::instance()->id;
        $roleid = $this->assignUserCapability('moodle/CAPABILITYNAME', $contextid);
 
        $params = array(PARAM1, PARAM2, ...);
 
        $returnvalue = COMPONENT_external::FUNCTION_NAME($params);
 
        // We need to execute the return values cleaning process to simulate the web service server
        $returnvalue = external_api::clean_returnvalue(COMPONENT_external::FUNCTION_NAME_returns(), $returnvalue);
 
        // Some PHPUnit assert
        $this->assertEquals(EXPECTED_VALUE, RETURNED_VALUE);
 
        // Call without required capability
        $this->unassignUserCapability('moodle/CAPABILITYNAME', $contextid, $roleid);
        $this->expectException(required_capability_exception::class);
        $returnvalue = COMPONENT_external::FUNCTION_NAME($params);
 
    }
}
</code>
 
But the quickest way is most likely to look at some example like course/tests/courseexternallib_test.php - get_categories (MDL-33995). Also read [[Writing PHPUnit tests]].
 
=== Coding style ===
* external functions often check many capabilities. Remember to assign the correct one to the $USER and also test for exception when the $USER doesn't have them.
 
 
 
[[Category:Unit testing]][[Category:Web_Services]]

Revision as of 12:34, 6 February 2019

Moodle 2.3 Since Moodle 2.3 we are using PHP Unit framework. Writing a unit test before writing an external function will end up to be very helpful. The easiest external function is not an easy task, as you can see in How to contribute a web service function to core. When writing PHPUnit tests you will:

  • discover use cases you didn't think about.
  • understand the feelings and the needs of the web service client developer.
  • end up with a function usable by everybody, not only by your own client.
  • reach integration way faster as you joined a proof of validity
  • make the QA process a breeze

How to run a PHPUnit test

you should read first the PHPUnit Moodle documentation to have a grasp of PHPUnit in Moodle.

How to write an external function PHPUnit test

If it doesn't exist create a COMPONENTFOLDER/tests/externallib_test.php file.

<?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**

* COMPONENT External functions unit tests
*
* @package    core_component
* @category   external
* @copyright  20XX Your Name
* @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

defined('MOODLE_INTERNAL') || die();

require_once($CFG->dirroot . '/webservice/tests/helpers.php'); require_once($CFG->dirroot . '/COMPONENT/externallib.php');

class COMPONENT_external_testcase extends externallib_advanced_testcase {

   /**
    * Test
    */
   public function test_FUNCTION_NAME() {
       global $USER;
       $this->resetAfterTest(true);
       // Set the required capabilities by the external function
       $contextid = context_XXXX::instance()->id;
       $roleid = $this->assignUserCapability('moodle/CAPABILITYNAME', $contextid);
       $params = array(PARAM1, PARAM2, ...);
       $returnvalue = COMPONENT_external::FUNCTION_NAME($params);
       // We need to execute the return values cleaning process to simulate the web service server
       $returnvalue = external_api::clean_returnvalue(COMPONENT_external::FUNCTION_NAME_returns(), $returnvalue);
       // Some PHPUnit assert
       $this->assertEquals(EXPECTED_VALUE, RETURNED_VALUE);
       // Call without required capability
       $this->unassignUserCapability('moodle/CAPABILITYNAME', $contextid, $roleid);
       $this->expectException(required_capability_exception::class);
       $returnvalue = COMPONENT_external::FUNCTION_NAME($params);
   }

}

But the quickest way is most likely to look at some example like course/tests/courseexternallib_test.php - get_categories (MDL-33995). Also read Writing PHPUnit tests.

Coding style

  • external functions often check many capabilities. Remember to assign the correct one to the $USER and also test for exception when the $USER doesn't have them.