classification
Title: More matchers in unittest.mock
Type: enhancement Stage:
Components: Library (Lib) Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: FR4NKESTI3N, Petter S, lisroach, xtreak
Priority: normal Keywords:

Created on 2019-01-04 11:04 by Petter S, last changed 2019-01-11 08:32 by Petter S.

Messages (7)
msg332968 - (view) Author: Petter S (Petter S) * Date: 2019-01-04 11:04
The ``ANY`` object in ``unittest.mock`` is also pretty useful when verifying dicts in tests:

    self.assertEqual(result, {
        "message": "Hi!",
        "code": 0,
        "id": mock.ANY
    })

Then it does not matter what the (presumably randomly generated) id is. For the same use cases, objects like ``APPROXIMATE`` (for approximate floating-point matching) and ``MATCHES`` (taking a boolean lambda) would be pretty useful, I think.
msg333210 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python triager) Date: 2019-01-08 05:42
Looking at the code ANY is simply implemented with __eq__ always returning True at https://github.com/python/cpython/blob/e61cc481e02b758c8d8289163102c236d0658a55/Lib/unittest/mock.py#L1957 . I am not sure how APPROXIMATE can be implemented in terms of floating point like rounding up or down? Do you have any examples in mind over a sample implementation or example of how they should behave in various scenarios?
msg333222 - (view) Author: Petter S (Petter S) * Date: 2019-01-08 11:07
Yes, something like this:

    class APPROXIMATE:
        """Takes a floating point number and implements approximate equality."""

        def __init__(self, value):
            self.value = value

        def __eq__(self, other):
            return abs(self.value - other) / (abs(self.value) + abs(other)) < 1e-6

        def __repr__(self):
            return f"APPROXIMATE({self.value})"


Then the following would hold:

    got = {
    "name": "Petter",
    "length": 1.900001
    }

    expected = {
    "name": "Petter",
    "length": APPROXIMATE(1.9)
    }

    assert got == expected

But not

    got["length"] = 1.8
    assert got == expected
msg333223 - (view) Author: Yash Aggarwal (FR4NKESTI3N) * Date: 2019-01-08 11:29
I feel it would be better to have tolerance as an argument.
msg333330 - (view) Author: Petter S (Petter S) * Date: 2019-01-09 16:05
Agreed! The code above was a quick example. There are also functions in the standard library for approximate float matching that the "real" code would use.
msg333420 - (view) Author: Lisa Roach (lisroach) * (Python committer) Date: 2019-01-10 21:42
APPROXIMATE feels like it might lead to code smell to me, if I know roughly what the float should be why would I not want to test it for exactness? It could end up hiding inconsistencies the tests should be catching.
msg333443 - (view) Author: Petter S (Petter S) * Date: 2019-01-11 08:32
I am of the opposite opinion. :-) 

> if I know roughly what the float should be why would I not want to test it for exactness?

When testing algorithms, it is often the case that the answer should be mathematically exactly 2, but due to floating-point inexactness it becomes, say, 1.9999999997 in practice. If I then test for exactly 1.9999999997 the test becomes very brittle and sensitive for e.g. order of multiplications.

Testing floating point numbers with a relative error is essential in many application.
History
Date User Action Args
2019-01-11 08:32:44Petter Ssetmessages: + msg333443
2019-01-10 21:42:05lisroachsetnosy: + lisroach
messages: + msg333420
2019-01-09 16:05:39Petter Ssetmessages: + msg333330
2019-01-08 11:29:52FR4NKESTI3Nsetnosy: + FR4NKESTI3N
messages: + msg333223
2019-01-08 11:07:48Petter Ssetmessages: + msg333222
2019-01-08 05:42:51xtreaksetnosy: + xtreak

messages: + msg333210
versions: + Python 3.8
2019-01-04 11:04:51Petter Screate