From c6a6a2fc4c8613010e64b5862ce95f3c7d6314db Mon Sep 17 00:00:00 2001 From: Phil Davis Date: Tue, 26 Feb 2019 15:49:40 +0545 Subject: [PATCH 1/2] How to add new acceptance test steps --- .../pages/core/acceptance-tests.adoc | 120 ++++++++++++++++-- 1 file changed, 106 insertions(+), 14 deletions(-) diff --git a/modules/developer_manual/pages/core/acceptance-tests.adoc b/modules/developer_manual/pages/core/acceptance-tests.adoc index 540188e65a..98564d623e 100644 --- a/modules/developer_manual/pages/core/acceptance-tests.adoc +++ b/modules/developer_manual/pages/core/acceptance-tests.adoc @@ -669,40 +669,132 @@ CI will fail, and so the developer will notice this scenario and will have to co [[how-to-add-a-new-feature]] == How to Add New Test Steps -To do - write this section. The following is some code that was already in this document: +See http://behat.org/en/latest/user_guide.html[the Behat User Guide] for information about writing test step code. -The first thing we need to do is create a new file for the context; we'll name it `TaskToTestContext.php`. -In the file, we'll add the code snippet below: +In addition to that, follow these guidelines. + +=== Given Steps + +The code of a `Given` step should achieve the desired system state by whatever means is quick to execute. +Typically use a public API if available, rather than running an `occ` command via the testing app or entering data in the webUI. + +If there is a simple way to gain confidence that the `Given` step was successful, then do it. +Typically this will check a status code returned in the API response. +Doing simple confidence checks in `Given` steps makes it easier to catch some unexpected problem during the scenario `Given` section. + +Here's example code for a `Given` step: + +[source,php] +---- +/** + * @Given the administrator has changed the password of user :user to :password + * + * @param string $user + * @param string $password + * + * @return void + * @throws \Exception + */ +public function adminHasChangedPasswordOfUserTo( + $user, $password +) { + $this->adminChangesPasswordOfUserToUsingTheProvisioningApi( + $user, $password + ); + $this->theHTTPStatusCodeShouldBe( + 200, + "could not change password of user $user" + ); +} +---- + +The code calls the method for the `When` step and then checks the HTTP status code. + +=== When Steps + +The code of a `When` step should perform the action but not check its result. +A `When` step should not ordinarily fail. +Often a `When` step will save the response. +It is the responsibility of later `Then` steps to decide if the scenario passed or failed. + +Here's example code for a `When` step: [source,php] ---- -response = UserHelper::editUser( + $this->getBaseUrl(), + $user, + 'password', + $password, + $this->getAdminUsername(), + $this->getAdminPassword() + ); +} +---- + +The code saves the response so that later `Then` steps can examine it. -use Behat\Behat\Context\Context; +=== Then Steps -require __DIR__ . '/../../vendor/autoload.php'; +The code of a `Then` step should check some result of the `When` action. +Often it will find information in the saved response and assert something. +Here's example code for a `Then` step: + +[source,php] +---- /** - * Example Context. + * @Then /^the groups returned by the API should include "([^"]*)"$/ + * + * @param string $group + * + * @return void */ -class ExampleContext implements Context { - use Webdav; +public function theGroupsReturnedByTheApiShouldInclude($group) { + $respondedArray = $this->getArrayOfGroupsResponded($this->response); + PHPUnit_Framework_Assert::assertContains($group, $respondedArray); } ---- -Here's example code for a scenario: +But a `Then` step may need to do actions of its own to retrieve more information about the state of the system. +For example, after changing a user password we could check that the user can still access some file: [source,php] ---- /** - * @When Sending a :method to :url with requesttoken + * @Then /^as "([^"]*)" (file|folder|entry) "([^"]*)" should exist$/ + * + * @param string $user + * @param string $entry + * @param string $path * - * @param string $method - * @param string $url + * @return void + * @throws \Exception */ -public function exampleFunction($method, $url) { +public function asFileOrFolderShouldExist($user, $entry, $path) { + $path = $this->substituteInLineCodes($path); + $this->responseXmlObject = $this->listFolder($user, $path, 0); + PHPUnit_Framework_Assert::assertTrue( + $this->isEtagValid(), + "$entry '$path' expected to exist but not found" + ); +} ---- +In the above example `listFolder` is called and does an API call to access the file and then asserts that the response has a valid etag. + == References For more information on Behat, and how to write acceptance tests using it, see http://behat.org/en/latest/guides.html[the Behat documentation]. From b83ae6fe23123809bfeabd12fdb2d9d75877b2fa Mon Sep 17 00:00:00 2001 From: Matthew Setter Date: Tue, 26 Feb 2019 11:42:16 +0100 Subject: [PATCH 2/2] Minor change to add new test steps structure This change makes three minor grammar fixes, and extracts the code examples out into example files. The main reason for that is that the adoc file is easier to read, and the source files can be linted. --- .../core/acceptance-tests/given-step.php | 21 +++++ .../then-step-with-actions.php | 19 +++++ .../core/acceptance-tests/then-step.php | 12 +++ .../core/acceptance-tests/when-step.php | 22 +++++ .../pages/core/acceptance-tests.adoc | 82 ++----------------- 5 files changed, 82 insertions(+), 74 deletions(-) create mode 100644 modules/developer_manual/examples/core/acceptance-tests/given-step.php create mode 100644 modules/developer_manual/examples/core/acceptance-tests/then-step-with-actions.php create mode 100644 modules/developer_manual/examples/core/acceptance-tests/then-step.php create mode 100644 modules/developer_manual/examples/core/acceptance-tests/when-step.php diff --git a/modules/developer_manual/examples/core/acceptance-tests/given-step.php b/modules/developer_manual/examples/core/acceptance-tests/given-step.php new file mode 100644 index 0000000000..ce54b195de --- /dev/null +++ b/modules/developer_manual/examples/core/acceptance-tests/given-step.php @@ -0,0 +1,21 @@ +/** + * @Given the administrator has changed the password of user :user to :password + * + * @param string $user + * @param string $password + * + * @return void + * @throws \Exception + */ +public function adminHasChangedPasswordOfUserTo( + $user, $password +) { + $this->adminChangesPasswordOfUserToUsingTheProvisioningApi( + $user, $password + ); + $this->theHTTPStatusCodeShouldBe( + 200, + "could not change password of user $user" + ); +} + diff --git a/modules/developer_manual/examples/core/acceptance-tests/then-step-with-actions.php b/modules/developer_manual/examples/core/acceptance-tests/then-step-with-actions.php new file mode 100644 index 0000000000..fe3059e5d5 --- /dev/null +++ b/modules/developer_manual/examples/core/acceptance-tests/then-step-with-actions.php @@ -0,0 +1,19 @@ +/** + * @Then /^as "([^"]*)" (file|folder|entry) "([^"]*)" should exist$/ + * + * @param string $user + * @param string $entry + * @param string $path + * + * @return void + * @throws \Exception + */ +public function asFileOrFolderShouldExist($user, $entry, $path) { + $path = $this->substituteInLineCodes($path); + $this->responseXmlObject = $this->listFolder($user, $path, 0); + PHPUnit_Framework_Assert::assertTrue( + $this->isEtagValid(), + "$entry '$path' expected to exist but not found" + ); +} + diff --git a/modules/developer_manual/examples/core/acceptance-tests/then-step.php b/modules/developer_manual/examples/core/acceptance-tests/then-step.php new file mode 100644 index 0000000000..fe760e295c --- /dev/null +++ b/modules/developer_manual/examples/core/acceptance-tests/then-step.php @@ -0,0 +1,12 @@ +/** + * @Then /^the groups returned by the API should include "([^"]*)"$/ + * + * @param string $group + * + * @return void + */ +public function theGroupsReturnedByTheApiShouldInclude($group) { + $respondedArray = $this->getArrayOfGroupsResponded($this->response); + PHPUnit_Framework_Assert::assertContains($group, $respondedArray); +} + diff --git a/modules/developer_manual/examples/core/acceptance-tests/when-step.php b/modules/developer_manual/examples/core/acceptance-tests/when-step.php new file mode 100644 index 0000000000..5543dc0464 --- /dev/null +++ b/modules/developer_manual/examples/core/acceptance-tests/when-step.php @@ -0,0 +1,22 @@ +/** + * @When the administrator changes the password of user :user to :password using the provisioning API + * + * @param string $user + * @param string $password + * + * @return void + * @throws \Exception + */ +public function adminChangesPasswordOfUserToUsingTheProvisioningApi( + $user, $password +) { + $this->response = UserHelper::editUser( + $this->getBaseUrl(), + $user, + 'password', + $password, + $this->getAdminUsername(), + $this->getAdminPassword() + ); +} + diff --git a/modules/developer_manual/pages/core/acceptance-tests.adoc b/modules/developer_manual/pages/core/acceptance-tests.adoc index 98564d623e..548b5bd297 100644 --- a/modules/developer_manual/pages/core/acceptance-tests.adoc +++ b/modules/developer_manual/pages/core/acceptance-tests.adoc @@ -686,26 +686,7 @@ Here's example code for a `Given` step: [source,php] ---- -/** - * @Given the administrator has changed the password of user :user to :password - * - * @param string $user - * @param string $password - * - * @return void - * @throws \Exception - */ -public function adminHasChangedPasswordOfUserTo( - $user, $password -) { - $this->adminChangesPasswordOfUserToUsingTheProvisioningApi( - $user, $password - ); - $this->theHTTPStatusCodeShouldBe( - 200, - "could not change password of user $user" - ); -} +include::example$core/acceptance-tests/given-step.php[] ---- The code calls the method for the `When` step and then checks the HTTP status code. @@ -721,27 +702,7 @@ Here's example code for a `When` step: [source,php] ---- -/** - * @When the administrator changes the password of user :user to :password using the provisioning API - * - * @param string $user - * @param string $password - * - * @return void - * @throws \Exception - */ -public function adminChangesPasswordOfUserToUsingTheProvisioningApi( - $user, $password -) { - $this->response = UserHelper::editUser( - $this->getBaseUrl(), - $user, - 'password', - $password, - $this->getAdminUsername(), - $this->getAdminPassword() - ); -} +include::example$core/acceptance-tests/when-step.php[] ---- The code saves the response so that later `Then` steps can examine it. @@ -755,45 +716,18 @@ Here's example code for a `Then` step: [source,php] ---- -/** - * @Then /^the groups returned by the API should include "([^"]*)"$/ - * - * @param string $group - * - * @return void - */ -public function theGroupsReturnedByTheApiShouldInclude($group) { - $respondedArray = $this->getArrayOfGroupsResponded($this->response); - PHPUnit_Framework_Assert::assertContains($group, $respondedArray); -} +include::example$core/acceptance-tests/then-step.php[] ---- -But a `Then` step may need to do actions of its own to retrieve more information about the state of the system. +However, a `Then` step may need to do actions of its own to retrieve more information about the state of the system. For example, after changing a user password we could check that the user can still access some file: [source,php] ---- -/** - * @Then /^as "([^"]*)" (file|folder|entry) "([^"]*)" should exist$/ - * - * @param string $user - * @param string $entry - * @param string $path - * - * @return void - * @throws \Exception - */ -public function asFileOrFolderShouldExist($user, $entry, $path) { - $path = $this->substituteInLineCodes($path); - $this->responseXmlObject = $this->listFolder($user, $path, 0); - PHPUnit_Framework_Assert::assertTrue( - $this->isEtagValid(), - "$entry '$path' expected to exist but not found" - ); -} ----- - -In the above example `listFolder` is called and does an API call to access the file and then asserts that the response has a valid etag. +include::example$core/acceptance-tests/then-step-with-actions.php[] +---- + +In the above example, `listFolder` is called and does an API call to access the file and then asserts that the response has a valid ETag. == References