測試 __eq__ 與 __ne__¶
This is an example of testing overriden __eq__
and __ne__
methods.
In this example objects are identified by the value of their attributes.
There is an example where attributes are of the same type and an example
where attributes are of different types.
To kill all mutants we have to exercise all possible methods and comparison branches in them, see source comments for more info.
Once we’ve stablished what is equal and how that compares to None
and itself
we can start testing comparisons by modifying the attribute values one by one.
Note that equality comparison works both ways, that is X == Y
is the same
as Y == X
so we test it that way.
Comment out the test_default_objects_are_always_equal()
method and one of
the assertNotEqual(sandwich_1, sandwich_2)
lines and re-test to see the
difference in results!
Reproducer¶
$ pip install nose
$ pip install https://github.com/sixty-north/cosmic-ray/zipball/master
$ cosmic-ray run --test-runner nose --baseline=10 example.json sandwich.py -- tests.py
$ cosmic-ray report example.json --full-report
程式碼¶
class Sandwich(object):
def __init__(self, meat = None, bread = None):
"""
@meat - string
@bread - string
Parameters identify the type of ingredients used.
"""
self.meat = meat
self.bread = bread
def __eq__(self, other):
if not other:
return False
return self.meat == other.meat and self.bread == other.bread
def __ne__(self, other):
return not self == other
class SandwichWithMayoAndEggs(Sandwich):
def __init__(self, meat = None, bread = None, mayo=True, eggs=2):
super(self.__class__, self).__init__(meat, bread)
self.mayo = mayo
self.eggs = eggs
def __eq__(self, other):
if not other:
return False
return self.meat == other.meat and self.bread == other.bread and \
self.mayo == other.mayo and self.eggs == other.eggs
import sandwich
import unittest
class TestSandwich(unittest.TestCase):
def setUp(self):
self.sandwich_1 = sandwich.Sandwich()
self.sandwich_2 = sandwich.Sandwich()
def test_default_objects_are_always_equal(self):
"""
Newly created objects with the same attribute values
(e.g. default ones) are always equal. At the same time
!= will return False for the same objects.
"""
self.assertEqual(self.sandwich_1, self.sandwich_2)
self.assertFalse(self.sandwich_1 != self.sandwich_2)
def test_object_does_not_equal_None(self):
"""
An object instance is never equal to None.
Tests the if statement in the __eq__ method.
"""
self.assertNotEqual(self.sandwich_1, None)
def test_objects_differing_by_one_attribute_are_not_equal(self):
"""
Objects are never equal if at least one attribute differs.
To test all attributes we loop over each at a time,
update the values and compare the objects.
"""
for atr in ['meat', 'bread']:
setattr(self.sandwich_1, atr, 'test')
setattr(self.sandwich_2, atr, '')
# comparison works both ways so test it both ways
self.assertNotEqual(self.sandwich_1, self.sandwich_2)
self.assertNotEqual(self.sandwich_2, self.sandwich_1)
setattr(self.sandwich_1, atr, '')
setattr(self.sandwich_2, atr, '')
class TestSandwichWithMayoAndEggs(unittest.TestCase):
def setUp(self):
self.sandwich_1 = sandwich.SandwichWithMayoAndEggs()
self.sandwich_2 = sandwich.SandwichWithMayoAndEggs()
def test_object_does_not_equal_None(self):
self.assertNotEqual(self.sandwich_1, None)
def test_default_values(self):
self.assertEqual(self.sandwich_1.mayo, True)
self.assertEqual(self.sandwich_1.eggs, 2)
def test_objects_differing_by_one_attribute_are_not_equal(self):
""" this time object attributes are of different types"""
# meat
self.sandwich_1.meat = 'Chicken'
self.sandwich_2.meat = ''
self.assertNotEqual(self.sandwich_1, self.sandwich_2)
self.assertNotEqual(self.sandwich_2, self.sandwich_1)
self.sandwich_1.meat = ''
self.sandwich_2.meat = ''
# bread
self.sandwich_1.bread = 'Baguette'
self.sandwich_2.bread = ''
self.assertNotEqual(self.sandwich_1, self.sandwich_2)
self.assertNotEqual(self.sandwich_2, self.sandwich_1)
self.sandwich_1.bread = ''
self.sandwich_2.bread = ''
# mayo
self.sandwich_1.mayo = True
self.sandwich_2.mayo = False
self.assertNotEqual(self.sandwich_1, self.sandwich_2)
self.assertNotEqual(self.sandwich_2, self.sandwich_1)
self.sandwich_1.mayo = False
self.sandwich_2.mayo = False
self.sandwich_1.eggs = 2
self.sandwich_2.eggs = 0
self.assertNotEqual(self.sandwich_1, self.sandwich_2)
self.assertNotEqual(self.sandwich_2, self.sandwich_1)
self.sandwich_1.eggs = 0
self.sandwich_2.eggs = 0
if __name__ == "__main__":
unittest.main()