Днес няма да си говорим за 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_
и failUnless
self.assertFalse(expr)
- още failIf
self.assertEqual(expected, actual)
- още assertEquals
и failUnlessEqual
self.assertAlmostEqual(expected, actual, places=7)
- още assertAlmostEquals
и failUnlessAlmostEqual
self.assertNotAlmostEqual(expected, actual, places=7)
- още assertNotAlmostEquals
и failIfAlmostEqual
self.assertRaises(self, excClass, callable, *args, **kwargs)
- още failUnlessRaises
setUp
и tearDown
)