Днес няма да си говорим за acceptance testing, quality assurance или нещо, което се прави от „по-низшия“ отдел във фирмата. Всичко тук е дело на програмиста.
Проектът идва с готово, подробно задание. Прави се дизайн. С него работата се разбива на малки задачи. Те се извършват последователно. За всяка от тях пишете кода и приключвате. Изискванията не се променят, нито се добавя нова функционалност.
Щом съм написал един код, значи ми остава единствено да го разцъкам - няколко print-а, малко пробване в main метода/функцията и толкова. Така или иначе няма да се променя. А ако (не дай си боже) това се случи - аз съм го писал, знам го, няма как да допусна грешка. Най-много да го поразцъкам още малко.
class Programmer(object):
# ...
def implementAChange(self, project, change):
files = self.openRelatedFiles(project, change)
while True:
self.attemptChange(change, files)
project.run()
result = self.clickAroundAndTest(project)
project.stop()
if result.successful(): break
self.commitCode(project, files)
self.hopeEverythingWentOK()
— Добре де… хващам се, че постоянно правя едно и също нещо като робот. Понеже е досадно, лесно ще забравя нещо. Пък и само ми губи времето. Човешката цивилизация не реши ли тоя вид проблеми с някакви машини? Май се казваха компютри?
— Защо просто не си напишеш програма, която да го прави вместо теб?
class Interval(object):
def __init__(self, left, right): self.left, self.right = left, right
def __repr__(self): return "Interval(%s, %s)" % (self.left, self.right)
def __eq__(self, other):
return isinstance(other, Interval) and \
(self.left, self.right) == (other.left, other.right)
def leftOpen(self): return self.left == None
def rightOpen(self): return self.right == None
def containsNumber(self, number):
if self.leftOpen() and self.rightOpen(): return true
if self.leftOpen(): return number <= self.right
if self.rightOpen(): return self.left <= number
return self.left < number < self.right
def intersect(self, other):
extr = lambda a, b, func: func(a, b) if not None in (a, b) else a or b
return Interval(
extr(self.left, other.left, max),
extr(self.right, other.right, min))
__and__ = intersect
class IntervalTest:
def testContainsNumber(self):
interval = Interval(None, 0)
твърдя_че("interval съдържа -3")
твърдя_че("interval съдържа 0")
твърдя_че("interval не съдържа 9")
твърдя_че("interval.leftOpen() е истина")
твърдя_че("interval.rightOpen() е лъжа")
def testIntersects(self):
твърдя_че("сечението на [0, 10] с [5, None] е [5, 10]")
твърдя_че("сечението на [None, 0] с [None, 42] е [None, 0]")
твърдя_че("сечението на [None, 20] с [-20, None] е [-20, 20]")
твърдя_че("сечението на [None, 0] с [-10, None] е [-10, 0]")
class IntervalTest(unittest.TestCase):
def testContainsNumber(self):
interval = Interval(None, 0)
self.assertTrue(interval.containsNumber(-3))
self.assertTrue(interval.containsNumber(0))
self.failIf(interval.containsNumber(9))
self.assertTrue(interval.leftOpen())
self.failIf(interval.rightOpen())
def testIntersects(self):
self.assertEquals(
Interval(5, 10), Interval(0, 10) & Interval(5, None))
self.assertEquals(
Interval(None, 0), Interval(None, 42) & Interval(None, 0))
self.assertEquals(
Interval(-20, 20), Interval(None, 20) & Interval(-20, None))
self.assertEquals(
Interval(-10, 0), Interval(None, 0) & Interval(-10, None))
if __name__ == "__main__":
unittest.main()
.F ====================================================================== FAIL: testIntersects (__main__.IntervalTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "", line 52, in testIntersects AssertionError: Interval(-10, 0) != Interval(-10, None) ---------------------------------------------------------------------- Ran 2 tests in 0.001s FAILED (failures=1)
vocabulary = {
"група": ("test case", unittest.TestCase),
"сценарий": ("test method",
[_ for _ in dir(YourTestCase) if _.startswith("test")]),
"твърдение": ("assertion",
[_ for _ in dir(unittest.TestCase) if re.match("assert|fail", _)])
}
Важно. Не бъркайте ключовата дума assert с методите за твърдения в тестовете. Първото служи да прекратите програмата ако изпадне в невалидно състояние. Второто е част от библиотеката за тестове.
Всички методи имат опционален последен аргумент msg - текстово съобщение, което ще се покаже ако теста пропадне.
self.assertTrue(expr) - още assert_ и failUnlessself.assertFalse(expr) - още failIfself.assertEqual(expected, actual) - още assertEquals и failUnlessEqualself.assertAlmostEqual(expected, actual, places=7) - още assertAlmostEquals и failUnlessAlmostEqualself.assertNotAlmostEqual(expected, actual, places=7) - още assertNotAlmostEquals и failIfAlmostEqualself.assertRaises(self, excClass, callable, *args, **kwargs) - още failUnlessRaisessetUp и tearDown)