290 votes

pytest : assert almost equal

Comment faire assert almost equal avec py.test pour les flottants sans avoir recours à quelque chose comme :

assert x - 0.00001 <= y <= x + 0.00001

Plus précisément, il sera utile de connaître une solution soignée pour comparer rapidement des paires de flotteurs, sans les déballer :

assert (1.32, 2.4) == i_return_tuple_of_two_floats()

4 votes

Py.test a maintenant une fonctionnalité qui fait cela.

2 votes

Voir cette réponse pour une description de cette fonctionnalité

470voto

dbw Points 2246

J'ai remarqué que cette question portait spécifiquement sur py.test. py.test 3.0 comprend un approx() (enfin, une vraie classe) qui est très utile à cet effet.

import pytest

assert 2.2 == pytest.approx(2.3)
# fails, default is ± 2.3e-06
assert 2.2 == pytest.approx(2.3, 0.1)
# passes

# also works the other way, in case you were worried:
assert pytest.approx(2.3, 0.1) == 2.2
# passes

La documentation est ici : https://docs.pytest.org/en/latest/reference/reference.html?highlight=approx#pytest.approx

28 votes

Joli ! J'ai aussi découvert que cela fonctionne aussi pour les séquences de nombres, par ex. assert [0.1 + 0.2, 0.2 + 0.4] == pytest.approx([0.3, 0.6])

10 votes

@Mr Kriss Et même pour les dicts : assert {'a': 0.1+0.2} == pytest.approx({'a': 0.3})

6 votes

Cela ne fonctionne pas pour les listes de listes : par exemple, assert [[0.1 + 0.2], [0.2 + 0.4]] == pytest.approx([[0.3], [0.6]]) conduit à un TypeError . Si l'on constate que la méthode de Numpy np.testing.assert_allclose([[0.1 + 0.2], [0.2 + 0.4]], [[0.3], [0.6]]) (voir réponse ci-dessous) a fonctionné pour ce cas.

53voto

yurib Points 2907

Vous devrez préciser ce qui est "presque" pour vous :

assert abs(x-y) < 0.0001

pour s'appliquer aux tuples (ou à toute séquence) :

def almost_equal(x,y,threshold=0.0001):
  return abs(x-y) < threshold

assert all(map(almost_equal, zip((1.32, 2.4), i_return_tuple_of_two_floats())

8 votes

La question est de savoir comment le faire "sans recourir à quelque chose comme" ceci

0 votes

J'interprète "quelque chose comme ça" comme une expression répétitive et maladroite comme x - d <= y <= x+d Il semble que c'est également ce que le PO voulait dire. Si vous ne souhaitez pas spécifier explicitement le seuil pour "presque", voir la réponse de @jiffyclub.

2 votes

Py.test a maintenant une fonctionnalité qui fait cela. J'ai ajouté une réponse à ce sujet.

40voto

jiffyclub Points 161

Si vous avez accès à NumPy, il dispose d'excellentes fonctions de comparaison en virgule flottante qui permettent déjà de faire des comparaisons par paire avec numpy.testing .

Alors vous pouvez faire quelque chose comme :

numpy.testing.assert_allclose(i_return_tuple_of_two_floats(), (1.32, 2.4))

20voto

kobejohn Points 2485

Ces réponses existent depuis longtemps, mais je pense que le moyen le plus simple et le plus lisible est d'utiliser unittest pour sa fonction beaucoup de belles affirmations sans l'utiliser pour la structure de test.

Obtenir les assertions, ignorer le reste de unittest.TestCase

(sur la base de cette réponse )

import unittest

assertions = unittest.TestCase('__init__')

Faites quelques affirmations

x = 0.00000001
assertions.assertAlmostEqual(x, 0)  # pass
assertions.assertEqual(x, 0)  # fail
# AssertionError: 1e-08 != 0

Mise en œuvre du test de déballage automatique des questions originales

Utilisez simplement * pour décompresser votre valeur de retour sans avoir à introduire de nouveaux noms.

i_return_tuple_of_two_floats = lambda: (1.32, 2.4)
assertions.assertAlmostEqual(*i_return_tuple_of_two_floats())  # fail
# AssertionError: 1.32 != 2.4 within 7 places

1 votes

Cela présente l'avantage, par rapport à toutes les réponses précédentes, de pouvoir utiliser des collections et d'affirmer qu'elles sont égales à +1.

14voto

validname Points 159

Si vous voulez quelque chose qui fonctionne non seulement avec les flottants mais aussi avec les décimales, vous pouvez utiliser la fonction de python math.isclose :

    # - rel_tol=0.01` is 1% difference tolerance.
    assert math.isclose(actual_value, expected_value, rel_tol=0.01)

Docs - https://docs.python.org/3/library/math.html#math.isclose

0 votes

La tolérance relative (ou différence en pourcentage) est pratique à utiliser dans certains cas, par exemple dans le domaine scientifique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X