Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python unittest fail caused by rounding error

I build the class for geometric transformation. When I run a Unit test it fails because of rounding errors coming from the operations inside my methods.

In my test I compare the result from one of the method which should return the point (2,2,0), but because of rounding errors it returns (1.9999999999999996, 1.9999999999999996, 0.0)

Finding files... done.
Importing test modules ... done.

** DEBUG_45 from the method point=(1.9999999999999996, 1.9999999999999996, 0.0)
======================================================================
FAIL: testPointCoord (vectOper.test.TestNearestPoint.TestNearestPoint)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\src\vectOper\test\TestNearestPoint.py", line 14, in testPointCoord
self.assertEqual(pointCoord, (2,2,0), "nearest point failed")
AssertionError: nearest point failed

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)

From the calculation point of view it is acceptable, but I don't want my code to fail on the simple unit test.

import unittest
from vectOper.nearestPoint import NearestPoint

class TestNearestPoint(unittest.TestCase):

    def testPointCoord(self):
        nearestPoint = NearestPoint()
        pointCoord = nearestPoint.pointCoord(samplePoint=(2,2,2),lineStart=(0,0,0), lineVect=(1,1,0))
        self.assertEqual(pointCoord, (2,2,0), "nearest point failed")

What is a correct way to resolve problem like that? Obviously I cannot round up the output numbers or convert them to integers as normally it is not the case. Is there a way to code unit test to ignore rounding error? Is there any other way to resolve problem?

Edit: The question can be solved by using self.assertAlmostEqual as rightly suggested in another answer but the problem is that I need to test entrance of a tuple. After all suggestions I try to do:

def testPointCoord(self):
    nearestPoint = NearestPoint()
    pointCoord = nearestPoint.pointCoord(samplePoint=(2,2,2),lineStart=(0,0,0), lineVect=(1,1,0))
    self.assertAlmostEqual(pointCoord[0], 2, places=7, msg="nearest point x-coodr failed")
    self.assertAlmostEqual(pointCoord[1], 2, places=7, msg="nearest point y-coodr failed")
    self.assertAlmostEqual(pointCoord[2], 0, places=7, msg="nearest point z-coodr failed")

but I need to automatise it somehow as later I need to test a list of tuples as the sample points' coordinates for a vector field.

The solution suggested as a duplicate is only a half measure as it would be a bit tedious write 300 more comparisons if there is 100 tuples in the list.

like image 920
tomasz74 Avatar asked Oct 02 '22 23:10

tomasz74


1 Answers

Why don't you use assertAlmostEqual in each dimension using map? I don`t have access to your class, so i wrote a similar example here:

from unittest import TestCase

class Test_Tuple_Equality(TestCase):
    def test_tuple_equality_True(self):
        p1 = (0.00000001, 0.00000000001, 0)
        p2 = (0,0,0)
        map(lambda x, y: self.assertAlmostEqual(x,y), p1, p2)

    def test_tuple_equality_False(self):
        p1 = (0.00000001, 0.00000000001, 0)
        p2 = (1,0,0)
        map(lambda x, y: self.assertAlmostEqual(x,y), p1, p2)

Map will transform your a n-dimension tuple comparisson into n floats comparissons.

You can even create a compare_points function, like:

def compare_points(self, p1, p2):
    map(lambda x,y: self.assertAlmostEqual(x,y), p1,p2)

And then use it in your tests

Another solution is to use numpy`s method for that:

import numpy

>>>numpy.testing.assert_almost_equal((2,2,0), (1.9999999999,2,0), decimal=7, err_msg='', verbose=True)

Numpy is a pain to install, but, if you already use it, it would be the best fit.

like image 64
Lucas Ribeiro Avatar answered Oct 13 '22 00:10

Lucas Ribeiro