[python] coverage.py (how to 100% ?)

feliks28

Пытаюсь освоить Ned Batchelder's coverage.py, но засыпаюсь в самом интуитивно простом:

class Math:
def multy(self, a, b):
return a * b

#!/usr/local/bin/python
import unittest
import myfile
class MyTest(unittest.TestCase):
def testMultiplication(self):
m = myfile.Math
self.assertEqual(m.multy(4, 5 20)
if __name__ == '__main__':
import coverage
coverage.use_cache(0)
coverage.start
suite = unittest.TestLoader.loadTestsFromTestCase(MyTest)
unittest.TextTestRunner(verbosity=2).run(suite)
coverage.stop
coverage.report(myfile)
Запускаю utest.py и он выдает:
testMultiplication (__main__.MyTest) ... ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Name Stmts Exec Cover Missing
--------------------------------------
myfile 3 1 33% 1-2

Т.е. "class Math:" и "def multy(self, a, b):" не покрывается... А как для них вообще нужно тесты написать (или что изменить чтобы не пестрили "#pragma: no cover" по всему коду?...

feliks28

Блин, вот как обычно, стоит только написать, как сразу сам найдешь ответ:

The class and def lines are executedwhen the module is imported, not when they are called, so you have tomake sure to begin the coverage analysis before importing your module.
Переносим "import myfile" в main на следующую строчку после "coverage.start", и оно работает, как интуиция и подсказывала

conv3rsje

Очень рекомендую вместо unittest использовать python nose
У него при запуске тестов можно указать, нужно ли использовать проверку покрытия тестов
nosetests -v --with-coverage --cover-package=package.to.check --cover-erase ...

И вообще он гораздо проще и приятнее, нежели стандартный unittest
Пример с генерируемыми тестами и проверкой покрытия (орфография и пунктуация авторского модуля сохранены :))
$ cat package.py
#!/usr/bin/env python

class Math:
def multy(self, a, b):
return a * b
$ cat test_package.py
#!/usr/bin/env python

import nose
from nose.tools import *

import package

def test_mul:
def _check_mul(f, a, b, r):
assert_equals(f(a, b r, "Incorrect result")
m = package.Math
yield _check_mul, m.multy, 2, 2, 4
yield _check_mul, m.multy, -2, -2, 4
yield _check_mul, m.multy, 2, -2, -4
yield _check_mul, m.multy, 0, 100, 0
$ nosetests -v --with-coverage
test_package.test_mul(<bound method Math.multy of <package.Math instance at 0xa44df8c>>, 2, 2, 4) ... ok
test_package.test_mul(<bound method Math.multy of <package.Math instance at 0xa44df8c>>, -2, -2, 4) ... ok
test_package.test_mul(<bound method Math.multy of <package.Math instance at 0xa44df8c>>, 2, -2, -4) ... ok
test_package.test_mul(<bound method Math.multy of <package.Math instance at 0xa44df8c>>, 0, 100, 0) ... ok

Name Stmts Exec Cover Missing
---------------------------------------
package 3 3 100%
----------------------------------------------------------------------
Ran 4 tests in 0.019s

OK

feliks28

nose штука клевая, но у меня (Freebsd) работает странно: приходится вручную указывать модули для теста, сам nosetests их не находит; не находит doctest'ы в принципе и еще что-то по мелочи...
К тому же прелесть nose в nosetests, а мне проще пользуясь уже изученным unittest'овским API переопределить свой раскрашенный stream для TextTestRunner, а не разбираться куда в nose unittest'овские модули пораспихали и как переименовали.
Т.е. вещь определенно хорошая, но я не вижу чего-то такого особенного, из-за чего бы стоило в ней разбираться (не в nosetests, а в import nose.*). И беглый взгляд показывает, что если nose использовать не из оболочки, а из модуля, то это далеко не проще получится.....
Единственное что мне в nose понравилось существенно больше, так это tags. Но можно вместо них в unittest наборы suite использовать.
p.s. Кстати (не к nose, а к тестированию вдруг кто-нибудь ссылку на таксономию не знает.

conv3rsje

но я не вижу чего-то такого особенного
Простое делается просто.
Для тестирования это очень важно. Посмотри какого размера у тебя кусок бессмысленного кода, и какой - осмысленного.
Структурно это те же unittest'ы, совместимые со стандартным по части вызовов.
Но удобнее
PS Может у тебя тесты исполняемые?
  --exe                 Look for tests in python modules that are executable.
Normal behavior is to exclude executable modules,
since they may not be import-safe [NOSE_INCLUDE_EXE]

feliks28

Ну, можно ведь и под unittest переписать покороче:
class MyTest(unittest.TestCase):
def test_mul(self):
m = package.Math
self.assertEqual(m.multy(2, 2 4)
self.assertEqual(m.multy(-2, -2 4)
self.assertEqual(m.multy(2, -2 -4)
self.assertEqual(m.multy(0, 100 0)
--exe помог, хотя файлы c справами -rw-rw-r--, без x

conv3rsje

Не, под бессмысленным я понимал вот этот код

if __name__ == '__main__':
import coverage
coverage.use_cache(0)
coverage.start
suite = unittest.TestLoader.loadTestsFromTestCase(MyTest)
unittest.TextTestRunner(verbosity=2).run(suite)
coverage.stop
coverage.report(myfile)

а также необходимость создавать классы для тестов. И это в языке где hello world пишется в один оператор!

feliks28

Ну, это мне понадобилось, т.к. таким образом могу TextTestRunner вызвать с параметром stream = ColorStream и раскрасить вывод (серый утомляет). А классы, кстати, не необходимость(я их для setUp и tearDown использую): для методов есть unittest.FunctionTestCase.
Оставить комментарий
Имя или ник:
Комментарий: