gonkey

repository·master·Indexed 18 days ago

https://github.com/lamoda/gonkey

A testing automation tool for services via their APIs, supporting REST/JSON and OpenAPI compliance. It features database seeding for PostgreSQL, MySQL, Aerospike, and Redis, external service mocking, and Allure report generation for integration with TMS like TestIT. Tests are defined in YAML and support variable assignment, regex validation, and multipart/form-data requests.

Tokens
17.7K
Snippets
53
Records
63
Agent score
63%

What's inside gonkey

  1. Overview of Gonkey testing automation

    master

    Gonkey is a testing automation tool designed to test services via their APIs. It works by sending pre-prepared requests to a service and verifying the responses. Test scenarios are described using YAML files.

    Key Features:

    • Supports REST/JSON APIs.
    • Validates service APIs against OpenAPI specifications.
    • Populates service databases using fixtures (supports PostgreSQL, MySQL, Aerospike, and Redis).
    • Provides mocks to simulate external services.
    • Can be used as a library integrated with unit tests.
    • Generates Allure reports with support for TMS integration (TestIT, Allure TestOps).
    • Includes a JSON-schema for YAML file autocompletion and validation.
  2. Seed databases using Fixtures

    master

    Gonkey uses fixture files (YAML) to seed databases before tests. You can specify PostgreSQL schemas using the schema.table_name syntax. Fixtures support inheritance, templates, and record linking to manage complex data sets efficiently.

    tables:
      posts:
        - $name: janes_post
          title: New post
          text: Post text
          author: Jane Dow
          created_at: 2016-01-01 12:30:12
          updated_at: 2016-01-01 12:30:12
    
      comments:
        - post_id: $janes_post.id
          content: A comment...
  3. How mocks are defined in test files

    master

    Mock behavior is defined in YAML files within the mocks section of a test case. Each mock service definition requires a strategy (how to respond) and can optionally include requestConstraints (validation of the incoming request). You can also specify a calls count to ensure the mock is hit a specific number of times.

    - name: Test with mocks
      ...
      mocks:
        service1:
          requestConstraints:
            - kind: nop
          strategy: constant
          body: '{"status": "ok"}'
          calls: 1
        service2:
          strategy: nop
      request:
        ...
  4. Inherit records across files using `$name` and `$extend`

    master

    You can inherit data from one record to another across different files.

    1. In the source file, assign a unique name to a record using the $name key.
    2. In the target file, use the $extend key with that name to inherit the record's fields.
    3. Ensure the target file includes the source file in its inherits list.

    Constraints:

    • Names assigned via $name must be unique across all loaded fixture files and must not collide with template names.
    • Record inheritance ($extend for records) only works between different files. It is not supported within the same file.
    • You cannot reference template fields using this method; you can only reference actual records.
    # fixtures/post.yaml
    tables:
      posts:
        - $name: regular_post
          title: Post title
          text: Some text
    # fixtures/deleted_post.yaml
    inherits:
      - post
    tables:
      posts:
        - $extend: regular_post
          is_deleted: true
  5. Perform database queries and assertions

    master

    After HTTP requests, you can execute SQL SELECT queries to verify data changes. The query results are compared against an expected list of JSON objects.

    Formats

    • Recommended Format: Use dbChecks to allow multiple queries per test.
    • Legacy Format: Use dbQuery and dbResponse directly in the test root (supports only one query).

    Features

    • Regexp Support: You can use $matchRegexp(pattern) within the dbResponse JSON strings to validate fields using regular expressions.
    • Parameterization: Use {{ .var }} syntax in dbQuery and dbResponse. Provide values via dbQueryArgs and dbResponseArgs in the cases section. To override the entire expected response for a specific case, use dbResponseFull.
    • Ignore Ordering: To avoid issues with ORDER BY requirements, set ignoreDbOrdering: true inside the comparisonParams section.
    # Recommended format with multiple checks
    - name: my test
      dbChecks:
        - dbQuery: "SELECT code, partner_id FROM mark_paid_schedule"
          dbResponse:
            - '{"code":"GIFT123456","partner_id":1}'
    
    # Parameterized query and response
      dbQuery: "SELECT code FROM table WHERE id = '{{ .id }}'"
      dbResponse:
        - '{"code":"{{ .expected_code }}"}'
      cases:
        - dbQueryArgs:
            id: "123"
          dbResponseArgs:
            expected_code: "ABC"
    
    # Ignoring result order
    comparisonParams:
      ignoreDbOrdering: true
    
    dbQuery: "SELECT id FROM users LIMIT 2"
    dbResponse:
      - '{"id": 2}'
      - '{"id": 1}'
  6. Define and use record templates with `$extend`

    master

    Templates allow you to define a base set of fields to avoid repetitive data in your fixtures. You can use the $extend keyword to inherit fields from a template and override only the specific fields required for a test.

    Templates can also inherit from other templates using $extend, provided the base template is defined earlier in the same file or in a file included via inherits.

    templates:
      dummy_client:
        name: Dummy Client Name
        age: 35
        ip: 127.0.0.1
        is_deleted: false
    
      dummy_deleted_client:
        $extend: dummy_client
        is_deleted: true
    
    tables:
      clients:
        - $extend: dummy_client
        - $extend: dummy_client
          name: Josh
        - $extend: dummy_deleted_client
          name: Jane
  7. Configure mock behavior in YAML test files

    master

    Mock behavior is defined within the mocks section of your YAML test files. You can define multiple services, each with its own requestConstraints (to validate incoming requests) and a strategy (to determine the response).

    Each mock service can also specify a calls count to ensure the service is called exactly the expected number of times.

    - name: Test with mocks
      ...
      mocks:
        service1:
          calls: 1
          requestConstraints:
            - kind: nop
          strategy: constant
          body: '{"status": "ok"}'
        service2:
          strategy: nop
      request:
        ...
  8. Run SQL queries and verify DB state

    master

    After an HTTP request, you can execute SQL SELECT queries to verify data changes in the database. The results are compared against an expected list of JSON objects.

    There are two ways to define DB checks:

    1. Legacy style: Using dbQuery and dbResponse directly at the test level.
    2. Current style: Using dbChecks which allows running multiple queries per test case.

    Query definition: dbQuery must be a SELECT statement that returns strings. Response definition: dbResponse is a list of JSON objects. You can use Regexp for matching values using the $matchRegexp syntax.

    # Current recommended style for multiple queries
    dbChecks:
      - dbQuery: >
          SELECT code, purchase_date, partner_id FROM mark_paid_schedule WHERE code = 'GIFT100000-000002'
        dbResponse:
          - '{"code":"GIFT100000-000002","purchase_date":"2330-02-02T13:15:11.912874","partner_id":1}'
          - '{"code":"$matchRegexp(GIFT([0-9]{6})-([0-9]{6}))","purchase_date":"2330-02-02T13:15:11.912874","partner_id":1}'
  9. Use Regexp for response validation

    master

    You can use $matchRegexp to validate response bodies using regular expressions. This works for both plain text bodies and specific fields within a JSON response.

    Plain text body:

    response:
      200: "$matchRegexp(^xy+z$)"

    JSON field validation:

    response:
      200: |
        {
          "id": "$matchRegexp([\\w-]+)",
          "result": [
            "$matchRegexp(ORDER[0]{3}[0-9])"
          ]
        }
        response:
            200: |
              {
                "id": "$matchRegexp([\\w-]+)",
                "jsonrpc": "$matchRegexp([12].0)",
                "result": [
                  "data": [
                      "$matchRegexp(ORDER[0]{3}[0-9])",
                      "$matchRegexp(ORDER[0]{3}[0-9])"
                  ],
                ]
              }
  10. Use Record Templates with `$extend`

    master

    Templates allow you to define a base set of fields and reuse them across multiple records, reducing boilerplate. Use the $extend keyword to inherit fields from a template. You can redefine specific fields in the record to override the template values.

    Note: A template can only be inherited if the parent template is already defined in the current file or in a file referenced via the inherits key.

    templates:
      dummy_client:
        name: Dummy Client Name
        age: 35
        ip: 127.0.0.1
        is_deleted: false
    
      dummy_deleted_client:
        $extend: dummy_client
        is_deleted: true
    
    tables:
      clients:
         - $extend: dummy_client
         - $extend: dummy_client
           name: Josh
         - $extend: dummy_deleted_client
           name: Jane
  11. Define test scenarios in YAML

    master

    Test cases are defined in YAML files. A single scenario can include:

    • name: Description of the test.
    • method: HTTP method (e.g., GET, POST).
    • path: The endpoint path.
    • query: Query parameters (the leading ? is optional).
    • headers: HTTP headers.
    • cookies: Cookie values.
    • fixtures: List of fixture names to load.
    • request: The request body (supports template variables like {{ .var }}).
    • response: Expected response status and body. Supports JSON or raw text.
    • comparisonParams: Configuration for response comparison:
      • ignoreValues: boolean
      • ignoreArraysOrdering: boolean
      • disallowExtraFields: boolean
    • cases: A list of specific input/output pairs for the scenario using requestArgs and responseArgs to populate templates.
    - name: "Scenario Name"
      method: GET
      path: /api/resource
      fixtures:
        - my_fixture
      response:
        200: |
          {
            "status": "ok"
          }
      cases:
        - requestArgs:
            param: value
          responseArgs:
            200:
              field: result
  12. Use variables in test descriptions

    master

    Gonkey supports variables in various test fields using the {{ $variable_name }} syntax. This allows for dynamic test definitions. Supported fields include:

    • method
    • description
    • path
    • query
    • headers
    • request
    • response
    • dbQuery
    • dbResponse
    • body (for mocks)
    • headers (for mocks)
    • requestConstraints (for mocks)
    • form (for multipart/form-data)

    Variables can be assigned via several methods, with priorities following the order of assignment (Test description > Previous request results > Current request results > Mock captures > Environment variables).

    - method: "{{ $method }}"
      description: "{{ $description }}"
      path: "/some/path/{{ $pathPart }}"
      query: "{{ $query }}"
      headers:
        header1: "{{ $header }}"
      request: '{"reqParam": "{{ $reqParam }}"}'
      response:
        200: "{{ $resp }}"
      mocks:
        server_mock:
          strategy: constant
          body: >
            {
              "message": "{{ $mockParam }}"
            }
          statusCode: 200
      dbQuery: >
        SELECT id, name FROM testing_tools WHERE id={{ $sqlQueryParam }}
      dbResponse:
        - '{"id": {{ $sqlResultParam }}, "name": "gonkey"}'