Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/utapyngo/pytest-unordered
Test equality of unordered sequences
https://github.com/utapyngo/pytest-unordered
Last synced: 27 days ago
JSON representation
Test equality of unordered sequences
- Host: GitHub
- URL: https://github.com/utapyngo/pytest-unordered
- Owner: utapyngo
- License: mit
- Created: 2019-11-26T05:01:53.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2024-03-13T15:24:21.000Z (9 months ago)
- Last Synced: 2024-03-14T15:25:21.814Z (9 months ago)
- Language: Python
- Homepage:
- Size: 42 KB
- Stars: 34
- Watchers: 4
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
- awesome-pytest - pytest-unordered - Test collection content, ignoring order. (Plugins)
README
# pytest-unordered: Test collection content, ignoring order
[![Build Status](https://github.com/utapyngo/pytest-unordered/actions/workflows/test.yml/badge.svg?branch=master)](https://github.com/utapyngo/pytest-unordered/actions/workflows/test.yml?query=branch%3Amaster)
[![Coverage Status](https://codecov.io/gh/utapyngo/pytest-unordered/branch/master/graph/badge.svg)](https://codecov.io/gh/utapyngo/pytest-unordered)
![Language](https://img.shields.io/github/languages/top/utapyngo/pytest-unordered)
[![Python Compatibility](https://img.shields.io/pypi/pyversions/pytest-unordered)](https://pypi.python.org/pypi/pytest-unordered)
[![PyPI](https://img.shields.io/pypi/v/pytest-unordered?color=rgb%2852%2C%20208%2C%2088%29)](https://pypi.org/project/pytest-unordered/)`pytest_unordered` allows you to write simple (pytest) assertions
to test whether collections have the same content, regardless of order.
For example:assert [1, 20, 300] == unordered([20, 300, 1])
It is especially useful when testing APIs that return some complex data structures
in an arbitrary order, e.g.:assert response.json() == {
"people": unordered(
# Here we test that the collection type is list
[
{
"name": "Alice",
"age": 20,
"children": unordered(
# Here the collection type is not important
{"name": "Bob", "age": 2},
{"name": "Carol", "age": 3},
),
},
{
"name": "Dave",
"age": 30,
"children": unordered(
{"name": "Eve", "age": 5},
{"name": "Frank", "age": 6},
),
},
]
),
}## Installation
pip install pytest-unordered
## Usage
### Basics
In most cases you just need the `unordered()` helper function:
from pytest_unordered import unordered
Compare list or tuples by wrapping your expected value with `unordered()`:
assert [1, 20, 300] == unordered([20, 300, 1]) # Pass
assert (1, 20, 300) == unordered((20, 300, 1)) # PassExcessive/missing items will be reported by pytest:
assert [1, 20, 300] == unordered([20, 300, 1, 300])
E Extra items in the right sequence:
E 300By default, the container type has to match too:
assert (1, 20, 300) == unordered([20, 300, 1])
E Type mismatch:
E !=### Nesting
A seasoned developer will notice that the simple use cases above
can also be addressed with appropriate usage
of builtins like `set()`, `sorted()`, `isinstance()`, `repr()`, etc,
but these solutions scale badly (in terms of boilerplate code)
with the complexity of your data structures.
For example: naively implementing order ignoring comparison
with `set()` or `sorted()` does not work with lists of dictionaries
because dictionaries are not hashable or sortable.
`unordered()` supports this out of the box however:assert [{"bb": 20}, {"a": 1}] == unordered([{"a": 1}, {"bb": 20}]) # Pass
The true value of `unordered()` lies in the fact that you
can apply it inside large nested data structures to skip order checking
only in desired places with surgical precision
and without a lot of boilerplate code.
For example:expected = unordered([
{"customer": "Alice", "orders": unordered([123, 456])},
{"customer": "Bob", "orders": [789, 1000]},
])actual = [
{"customer": "Bob", "orders": [789, 1000]},
{"customer": "Alice", "orders": [456, 123]},
]assert actual == expected
In this example we wrapped the outer customer list and the order list of Alice
with `unordered()`, but didn't wrap Bob's order list.
With the `actual` value of above (where customer order is different
and Alice's orders are reversed), the assertion will pass.
But if the orders of Bob would be swapped in `actual`, the assertion
will fail and pytest will report:E Differing items:
E {'orders': [1000, 789]} != {'orders': [789, 1000]}### Container type checking
As noted, the container types should be (by default) equal to pass the
assertion. If you don't want this type check, call `unordered()`
in a variable argument fashion (instead of passing
a container as single argument):assert [1, 20, 300] == unordered(20, 300, 1) # Pass
assert (1, 20, 300) == unordered(20, 300, 1) # PassThis pattern also allows comparing with iterators, generators and alike:
assert iter([1, 20, 300]) == unordered(20, 300, 1) # Pass
assert unordered(i for i in range(3)) == [2, 1, 0] # PassIf you want to enforce type checking when passing a single generator expression,
pass `check_type=True`:assert unordered((i for i in range(3)), check_type=True) == [2, 1, 0] # Fail
assert unordered((i for i in range(3)), check_type=True) == (i for i in range(2, -1, -1)) # Pass