Utils

AsyncCallQueue

Async callqueue wrapper. Stores information about each function call to synchronized queue.

@callinfo.acallqueue
async def func(a, b):
    return a + b

await func(1, 2)

>>> func.has_calls
True
>>> func.times_called
1
>>> func.next_call()
{'a': 1, 'b': 2}
class testsuite.utils.callinfo.AsyncCallQueue(func: Callable, *, checker: Optional[Callable[[str], None]] = None)[source]

Function wrapper that puts information about function call into async queue.

This class provides methods to wait/check function underlying function calls.

flush() None[source]

Clear call queue.

property has_calls: bool

Returns True if call queue is not empty.

next_call() dict[source]

Pops call from queue and return its arguments dict.

Raises CallQueueError if queue is empty

property times_called: int

Returns call queue length.

coroutine wait_call(timeout=10.0) dict[source]

Wait for fucntion to be called. Pops call from queue. Blocks if it’s empty.

Parameters:

timeout – timeout in seconds

Raises CallQueueTimeoutError if queue is empty for timeout seconds.

testsuite.utils.callinfo.acallqueue(func: Callable, *, checker: Optional[Callable[[str], None]] = None) AsyncCallQueue[source]

Turn function into async call queue.

Parameters:
  • func – async or sync callable, can be decorated with @staticmethod

  • checker – optional function to check whether or not operation on callqueue is possible

Matching

Testsuite provides utility to perform inexact pattern matching. This might be useful when comparing objects. For instance when checking HTTP handle response. Special objects with custom __eq__() method are used for pattern matching. You can use them instead of explicit value when comparing objects.

Here is example assertion on order/create handle response when you do not need to know exact order id returned by handle.

from testsuite.utils import matching

def test_order_create(...):
    response = await client.post('/order/create')
    assert response.status_code == 200

    assert response.json() == {
        'order_id': matching.uuid_string,
        ...
    }

String matching

Regular expressions

class testsuite.utils.matching.RegexString(pattern)[source]

Match string with regular expression.

assert response.json() == {
   'order_id': matching.RegexString('^[0-9a-f]*$'),
   ...
}

Predicates

  • any_string, matches any string

  • datetime_string, matches any datetime string using dateutil.parser

  • uuid_string, string is uuid, e.g.: d08535a5904f4790bd8f95c51c1f3cbe

  • objectid_string, String is Mongo objectid, e.g 5e64beab56d0bf70bd8eebcb

Integer matching

Gt

class testsuite.utils.matching.Gt(value)[source]

Value is greater than.

Example:

# Value must be > 10
assert value == matching.Gt(10)

Ge

class testsuite.utils.matching.Ge(value)[source]

Value is greater or equal.

Example:

# Value must be >= 10
assert value == matching.Ge(10)

Lt

class testsuite.utils.matching.Lt(value)[source]

Value is less than.

Example:

# Value must be < 10
assert value == matching.Lt(10)

Le

class testsuite.utils.matching.Le(value)[source]

Value is less or equal.

Example:

# Value must be <= 10
assert value == matching.Le(10)

Predicates

  • any_float

  • any_integer

  • any_numeric

  • positive_float

  • positive_integer

  • positive_numeric

  • negative_float

  • negative_integer

  • negative_numeric

  • non_negative_float

  • non_negative_integer

  • non_negative_numeric

Type matching

class testsuite.utils.matching.IsInstance(types)[source]

Match value by its type.

Use this class when you only need to check value type.

assert response.json() == {
   # order_id must be a string
   'order_id': matching.IsInstance(str),
   # int or float is acceptable here
   'weight': matching.IsInstance([int, float]),
   ...
}

Logical matching

And

class testsuite.utils.matching.And(*conditions)[source]

Logical AND on conditions.

# match integer is in range [10, 100)
assert num == matching.And([matching.Ge(10), matching.Lt(100)])

Or

class testsuite.utils.matching.Or(*conditions)[source]

Logical OR on conditions.

# match integers abs(num) >= 10
assert num == matching.Or([matching.Ge(10), matching.Le(-10)])

Not

class testsuite.utils.matching.Not(condition)[source]

Condition inversion.

Example:

# check value is not 1
assert value == matching.Not(1)

Partial dict

class testsuite.utils.matching.PartialDict(*args, **kwargs)[source]

Partial dictionary comparison.

Sometimes you only need to check dictionary subset ignoring all other keys. PartialDict is there for this purpose.

PartialDict is wrapper around regular dict() when instantiated all arguments are passed as is to internal dict object.

Example:

assert {'foo': 1, 'bar': 2} == matching.PartialDict({
    # Only check for foo >= 1 ignoring other keys
    'foo': matching.Ge(1),
})

Unordered list

testsuite.utils.matching.unordered_list(sequence, *, key=None)[source]

Unordered list comparison.

You may want to compare lists without respect to order. For instance, when your service is serializing std::unordered_map to array.

unordered_list can help you with that. It sorts both array before comparison.

Parameters:
  • sequence – Initial sequence

  • key – Sorting key function

Example:

assert [3, 2, 1] == matching.unordered_list([1, 2, 3])