Showing posts with label Codeception. Show all posts
Showing posts with label Codeception. Show all posts

Thursday, April 20, 2017

Automated API testing using Codeception

I was looking for a tool for testing an API, and I remembered about my old friend Codeception, which I used for some functional testing a while ago. I need now to test an API which is receiving requests and gives responses using JSON format.


Install Codeception via Composer
$ composer require "codeception/codeception" 
Create an alias so you do not have to write the entire path every time you execute a command:
$ alias codecept='./vendor/bin/codecept'
Create an API test suite:
$ codecept generate:suite api
Edit the configuration file  tests/api.suite.yml:


class_name: ApiTester
modules:
    enabled:
        - \Helper\Api
        - REST:
            url: "http://yourwebste.com/"
            depends: PhpBrowser
            part: Json

I will be using "Cest" format:  "Cest combines scenario-driven test approach with OOP design. In case you want to group a few testing scenarios into one you should consider using Cest format."

$ codecept generate:cest api UsersTestCest
This command is creating a PHP file under tests/api/.  
Before starting to write my first tests I need to find a way to pass a username and password to all tests, as it is needed for connecting to the API.
I can add any parameters to the api.suite.yml and access them inside my test classes:
api.suite.yml


class_name: ApiTester
modules:
    enabled:
        - \Helper\Api
        - REST:
            url: "http://yourwebsite.com"
            depends: PhpBrowser
            part: Json
params:
    username: "username"
    password: "password"


 And inside tests/api/UsersTestCest.php

class UsersTestCest
{
    private $username;
    private $password;

    public function _before(ApiTester $I)
}
    {
        $config = \Codeception\Configuration::config();
        $apiSettings = \Codeception\Configuration::suiteSettings('api', $config);
        $this->username = $apiSettings['params']['username'];
        $this->password = $apiSettings['params']['password'];
    }
}


The function "_before()" will be executed as it names says, before actual test functions, and it will  initialize the variables with values from api.suite.yml file.

Let's write the first test function:


public function createUser(ApiTester $I)
    {
        $action = "create_user";
        $I->haveHttpHeader('Content-Type', 'application/json');

        $array=[
            "action"=> $action,
            "username"=> $this->username,
            "key"=> $this->password,
            "user_username"=> "new_username",
            "user_email"=> "email@company.com",
            "user_password"=> "password"
            ]
        ];
        $string = json_encode($array);
        $I->sendPOST('api.php',$string);
        $I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK); // 200
        $I->seeResponseIsJson();
        $I->seeResponseMatchesJsonType([
            'operation' => 'string',
            'status' => 'string',
        ]);
    }

The link where the request is sent with the function sendPost() is the concatenation between the URL parameter from api.suite.yml and the first parameter in sentPost() function.
You can check if the response has HTTP status 200, if it is in JSON format and if the JSON has the expected structure.
Even more you can create your own assertions. These custom functions needs to be added to the file "tests/_support/ApiTester.php".
I will add a function to verify if the "status" field from the response is equal to '1'




<?php
namespace Helper;
class will be available in $I
use Codeception\TestInterface;

class Api extends \Codeception\Module
{
    public function checkOperationStatusSuccess()
    {
        $response = $this->getModule('REST')->response;
        $array = json_decode($response, true);
        $this->assertEquals('1',$array['status'],"Operation status should be '1' for success.");
    }
}

Run all tests with this command:
codecept run api -v

Or only tests from certain class:
$ codecept run tests/api/UsersTestCest.php -v
  
The tests are executed in the alphabetic order of the classes, but you can use the annotation "@depends" to indicated that your test function depends on other one(s). 
Enjoy!



Monday, February 1, 2016

About testing

1. Testing in Symfony

Roughly speaking, there are two types of test. Unit testing allows you to test the input and output of specific functions. Functional testing allows you to command a “browser” where you browse to pages on your site, click links, fill out forms and assert that you see certain things on the page.

1.1. Unit Tests

Unit tests are used to test your “business logic”, which should live in classes that are independent of Symfony. For that reason, Symfony doesn't really have an opinion on what tools you use for unit testing. However, the most popular tools are PhpUnit and PhpSpec.

1.2. Functional Tests

Creating really good functional tests can be tough so some developers skip these completely. Don't skip the functional tests! By defining some simple functional tests, you can quickly spot any big errors before you deploy them:

1.3. Testing JavaScript Functionality

The built-in functional testing client is great, but it can't be used to test any JavaScript behavior on your pages. If you need to test this, consider using the Mink or Selenium.

The above text is based on official Symfony documentation found here: http://symfony.com/doc/current/best_practices/tests.html

2. Acceptance testing

Acceptance testing can be performed by a non-technical person. That person can be your tester, manager or even client. If you are developing a web-application (and probably you are) the tester needs nothing more than a web browser to check that your site works correctly. You can reproduce a AcceptanceTester's actions in scenarios and run them automatically after each site change. Codeception keeps tests clean and simple, as if they were recorded from the words of AcceptanceTester.

2.1. Functional vs Acceptance testing

Acceptance tests are front-end only and you are testing whether you see the correct UI elements. This type of test never explicitly checks the database with a direct call. Think of it as only testing what an end-user would be able to see by clicking around in a browser.
Functional tests are similar to acceptance tests but they do check the database explicitly, something like $I→seeInDatabase() or $I→seeRecord(). Functional tests generally use a DOM parser instead of a browser (or phantomJS) like acceptance tests do – this is why JS is best left to acceptance tests.

3. All in one: Codeception

With Codeception you can run unit, functional and acceptance tests..
Why should I use Codeception instead of PHPUnit?
Being the most popular unit testing framework PHPUnit has very limited features for functional testing with Selenium or other backends. Codeception is PHPUnit on steroids. Everything you need for testing is built-in and works just out of the box. No more pain in configuring Selenium, data cleanup, writing XPaths, and fixtures.
Q: It looks just like Behat
Unlike Behat, Codeception tests are written in PHP. Thus, they are more flexible and easy in writing. Also you can use variables and operators, CSS and XPath locators in your tests. These features allow you to build a solid test automation platform for testing your web application. Codeception tests are simple and readable for your developers, managers, and QA team.
Q: We are planning to use Selenium IDE. Why Codeception?
Codeception works great with Selenium. But with Codeception you can write your tests in PHP. The main reason is: Selenium IDE tests are tightly bound to XPath locators. If you ever change anything in layout tests will fall. Codeception locators are more stable. You can use names, labels, button names and CSS to match elements on page. It's much easier to support the Codeception test then Selenium's one. Selenium just can't clean data between tests, can't check database values, or generate code coverage reports.
Q: Is Codeception a tool for testing legacy projects?
Sure you can use Codeception for black-box testing of your legacy application. But in the same manner you can start testing modern web application as well. With modules that integrates with all popular PHP frameworks you can start writing functional tests in seconds. Unit tests? Write them as you do in PHPUnit with some enhancement. Codeception keeps your tests in one place, makes them structured and readable.
Source: http://codeception.com/