Skip to content

Instantly share code, notes, and snippets.

@llupa
Last active September 13, 2023 13:38
Show Gist options
  • Save llupa/6625d24e075cc7cc6b26e6110fab04f7 to your computer and use it in GitHub Desktop.
Save llupa/6625d24e075cc7cc6b26e6110fab04f7 to your computer and use it in GitHub Desktop.
Team agreement on test categorisation

Introduction

I am writting this gist for two reasons:

  • I promised I will write it. Hey Dazz 👋
  • It seems that more than 1 (one) person has found this an interesting approach

A small preface: This was applied in an API project built with Symfony (API Platform). That is, there was no front-end, or HTML responses. This API project supports only json or json-ld. Our tests used the Symfony test-pack (PHPUnit and some Symfony helper classes).

The categories

As a team, after some cycles (sprints) of trying things out, we figured out that certain tests followed the same principles. Most of you have already read and even implmeneted them, but as a development team we saw that principles can be interpreted and this would cause confusion, or debates, all in good spirit, on "Where do I put this test case?".

In an attempt to have each member answer that question without the help of the team while developing, we came up with the following categories and the requirements they had to accept tests in them:

1: Unit tests

  • Tests that cover classes without dependencies, a.k.a __construct().
  • An exception can be made for classes who have at most a 1 level deep constructor whose dependencies are classes without dependencies.
  • All unit tests must extend TestCase from PHPUnit.

examples:

class Place 
{
    private string $where;
    
    public function __construct()
    {
       $this->where = '';
    }
}

class Time
{
    private string $when = '10:00';
}

class Appointment
{
    public function __construct(private Place $pace, private Time $time)
    {
    }
}

2: Integration tests

  • Tests that cover classes with dependencies from the Symfony service container.
  • Tests that cover classes that are Symfony services.
  • Tests whose main goal is a part of a functionality.
  • All integration tests must extend KernelTestCase from Symfony.

examples:

class AppointmentHandler
{
    public function __construct(private NoWorkCalendar $noWorkCalendar)
    {
    }

    public function handle(Appointment $appointment): void
    {
        $regionNoWorkCalendar = $this->noWorkCalendar->getRegionalCalendar($appointment->getCountry());        
        $result = $regionNoWorkCalendar->canHappen($appointment);
        // ...
    }
}

3: Functional tests

  • Tests that cover the same API resource or one endpoint.
  • Tests that cover multiple payloads but for the same endpoint.
    • query parameters alter the endpoint.
  • All functional tests must extend ApiTestCase from API Platform.
    • in particular cases (when a clueless client is needed) WebTestCase from Symfony is also acceptable.

examples:

POST /appointments
GET  /appointments
GET  /appointments/{id}
PUT  /appointments/{id}
...

4: Acceptance tests

  • Tests where more than one endpoint is called.
  • Tests where multiple query parameters combinations are needed.
  • Tests that represent a user-story.
  • All acceptance tests must extend ApiTestCase from API Platform.
  • in particular cases (when a clueless client is needed) WebTestCase from Symfony is also acceptable.

examples:

search:
  GET /appointment/search:
    - from
    - to
    - onlyAfter
    - allowWeekends
    - page
    - itemsPerPage
    - ...

a-person-made-a-mistake:
  POST   /appointments
  POST   /correction
  GET    /appointments
  DELETE /appointments/{id}
  POST   /appointments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment