unit testing framework
This commit is contained in:
18
.travis.yml
Normal file
18
.travis.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
dist: xenial
|
||||
language: python
|
||||
matrix:
|
||||
include:
|
||||
- python: 3.7
|
||||
env: TOXENV=flake8
|
||||
- python: 3.5
|
||||
env: TOXENV=py35
|
||||
- python: 3.6
|
||||
env: TOXENV=py36
|
||||
- python: 3.7
|
||||
env: TOXENV=py37
|
||||
- python: 3.7
|
||||
env: TOXENV=upy
|
||||
install:
|
||||
- pip install tox
|
||||
script:
|
||||
- tox
|
||||
BIN
bin/micropython
Executable file
BIN
bin/micropython
Executable file
Binary file not shown.
3
run_tests.py
Normal file
3
run_tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
import unittest
|
||||
|
||||
unittest.main('tests')
|
||||
1
tests/__init__.py
Normal file
1
tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from tests.test_microdot import TestMicrodot
|
||||
6
tests/test_microdot.py
Normal file
6
tests/test_microdot.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import unittest
|
||||
|
||||
|
||||
class TestMicrodot(unittest.TestCase):
|
||||
def test_foo(self):
|
||||
pass
|
||||
26
tox.ini
Normal file
26
tox.ini
Normal file
@@ -0,0 +1,26 @@
|
||||
[tox]
|
||||
envlist=flake8,py35,py36,py37,upy
|
||||
skip_missing_interpreters=True
|
||||
|
||||
[testenv]
|
||||
commands=python run_tests.py
|
||||
basepython=
|
||||
flake8: python3.7
|
||||
py35: python3.5
|
||||
py36: python3.6
|
||||
py37: python3.7
|
||||
upy: python3.7
|
||||
|
||||
[testenv:flake8]
|
||||
deps=
|
||||
flake8
|
||||
commands=
|
||||
flake8 microdot.py tests
|
||||
|
||||
[testenv:upy]
|
||||
whitelist_externals=sh
|
||||
commands=sh -c "bin/micropython run_tests.py"
|
||||
|
||||
[testenv:upy-mac]
|
||||
whitelist_externals=micropython
|
||||
commands=micropython run_tests.py
|
||||
224
unittest.py
Normal file
224
unittest.py
Normal file
@@ -0,0 +1,224 @@
|
||||
import sys
|
||||
|
||||
|
||||
class SkipTest(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AssertRaisesContext:
|
||||
|
||||
def __init__(self, exc):
|
||||
self.expected = exc
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, tb):
|
||||
if exc_type is None:
|
||||
assert False, "%r not raised" % self.expected
|
||||
if issubclass(exc_type, self.expected):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class TestCase:
|
||||
|
||||
def fail(self, msg=''):
|
||||
assert False, msg
|
||||
|
||||
def assertEqual(self, x, y, msg=''):
|
||||
if not msg:
|
||||
msg = "%r vs (expected) %r" % (x, y)
|
||||
assert x == y, msg
|
||||
|
||||
def assertNotEqual(self, x, y, msg=''):
|
||||
if not msg:
|
||||
msg = "%r not expected to be equal %r" % (x, y)
|
||||
assert x != y, msg
|
||||
|
||||
def assertAlmostEqual(self, x, y, places=None, msg='', delta=None):
|
||||
if x == y:
|
||||
return
|
||||
if delta is not None and places is not None:
|
||||
raise TypeError("specify delta or places not both")
|
||||
|
||||
if delta is not None:
|
||||
if abs(x - y) <= delta:
|
||||
return
|
||||
if not msg:
|
||||
msg = '%r != %r within %r delta' % (x, y, delta)
|
||||
else:
|
||||
if places is None:
|
||||
places = 7
|
||||
if round(abs(y-x), places) == 0:
|
||||
return
|
||||
if not msg:
|
||||
msg = '%r != %r within %r places' % (x, y, places)
|
||||
|
||||
assert False, msg
|
||||
|
||||
def assertNotAlmostEqual(self, x, y, places=None, msg='', delta=None):
|
||||
if delta is not None and places is not None:
|
||||
raise TypeError("specify delta or places not both")
|
||||
|
||||
if delta is not None:
|
||||
if not (x == y) and abs(x - y) > delta:
|
||||
return
|
||||
if not msg:
|
||||
msg = '%r == %r within %r delta' % (x, y, delta)
|
||||
else:
|
||||
if places is None:
|
||||
places = 7
|
||||
if not (x == y) and round(abs(y-x), places) != 0:
|
||||
return
|
||||
if not msg:
|
||||
msg = '%r == %r within %r places' % (x, y, places)
|
||||
|
||||
assert False, msg
|
||||
|
||||
def assertIs(self, x, y, msg=''):
|
||||
if not msg:
|
||||
msg = "%r is not %r" % (x, y)
|
||||
assert x is y, msg
|
||||
|
||||
def assertIsNot(self, x, y, msg=''):
|
||||
if not msg:
|
||||
msg = "%r is %r" % (x, y)
|
||||
assert x is not y, msg
|
||||
|
||||
def assertIsNone(self, x, msg=''):
|
||||
if not msg:
|
||||
msg = "%r is not None" % x
|
||||
assert x is None, msg
|
||||
|
||||
def assertIsNotNone(self, x, msg=''):
|
||||
if not msg:
|
||||
msg = "%r is None" % x
|
||||
assert x is not None, msg
|
||||
|
||||
def assertTrue(self, x, msg=''):
|
||||
if not msg:
|
||||
msg = "Expected %r to be True" % x
|
||||
assert x, msg
|
||||
|
||||
def assertFalse(self, x, msg=''):
|
||||
if not msg:
|
||||
msg = "Expected %r to be False" % x
|
||||
assert not x, msg
|
||||
|
||||
def assertIn(self, x, y, msg=''):
|
||||
if not msg:
|
||||
msg = "Expected %r to be in %r" % (x, y)
|
||||
assert x in y, msg
|
||||
|
||||
def assertIsInstance(self, x, y, msg=''):
|
||||
assert isinstance(x, y), msg
|
||||
|
||||
def assertRaises(self, exc, func=None, *args, **kwargs):
|
||||
if func is None:
|
||||
return AssertRaisesContext(exc)
|
||||
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
assert False, "%r not raised" % exc
|
||||
except Exception as e:
|
||||
if isinstance(e, exc):
|
||||
return
|
||||
raise
|
||||
|
||||
|
||||
|
||||
def skip(msg):
|
||||
def _decor(fun):
|
||||
# We just replace original fun with _inner
|
||||
def _inner(self):
|
||||
raise SkipTest(msg)
|
||||
return _inner
|
||||
return _decor
|
||||
|
||||
def skipIf(cond, msg):
|
||||
if not cond:
|
||||
return lambda x: x
|
||||
return skip(msg)
|
||||
|
||||
def skipUnless(cond, msg):
|
||||
if cond:
|
||||
return lambda x: x
|
||||
return skip(msg)
|
||||
|
||||
|
||||
class TestSuite:
|
||||
def __init__(self):
|
||||
self.tests = []
|
||||
def addTest(self, cls):
|
||||
self.tests.append(cls)
|
||||
|
||||
class TestRunner:
|
||||
def run(self, suite):
|
||||
res = TestResult()
|
||||
for c in suite.tests:
|
||||
run_class(c, res)
|
||||
|
||||
print("Ran %d tests\n" % res.testsRun)
|
||||
if res.failuresNum > 0 or res.errorsNum > 0:
|
||||
print("FAILED (failures=%d, errors=%d)" % (res.failuresNum, res.errorsNum))
|
||||
else:
|
||||
msg = "OK"
|
||||
if res.skippedNum > 0:
|
||||
msg += " (%d skipped)" % res.skippedNum
|
||||
print(msg)
|
||||
|
||||
return res
|
||||
|
||||
class TestResult:
|
||||
def __init__(self):
|
||||
self.errorsNum = 0
|
||||
self.failuresNum = 0
|
||||
self.skippedNum = 0
|
||||
self.testsRun = 0
|
||||
|
||||
def wasSuccessful(self):
|
||||
return self.errorsNum == 0 and self.failuresNum == 0
|
||||
|
||||
# TODO: Uncompliant
|
||||
def run_class(c, test_result):
|
||||
o = c()
|
||||
set_up = getattr(o, "setUp", lambda: None)
|
||||
tear_down = getattr(o, "tearDown", lambda: None)
|
||||
for name in dir(o):
|
||||
if name.startswith("test"):
|
||||
print("%s (%s) ..." % (name, c.__qualname__), end="")
|
||||
m = getattr(o, name)
|
||||
set_up()
|
||||
try:
|
||||
test_result.testsRun += 1
|
||||
m()
|
||||
print(" ok")
|
||||
except SkipTest as e:
|
||||
print(" skipped:", e.args[0])
|
||||
test_result.skippedNum += 1
|
||||
except:
|
||||
print(" FAIL")
|
||||
test_result.failuresNum += 1
|
||||
# Uncomment to investigate failure in detail
|
||||
#raise
|
||||
continue
|
||||
finally:
|
||||
tear_down()
|
||||
|
||||
|
||||
def main(module="__main__"):
|
||||
def test_cases(m):
|
||||
for tn in dir(m):
|
||||
c = getattr(m, tn)
|
||||
if isinstance(c, object) and isinstance(c, type) and issubclass(c, TestCase):
|
||||
yield c
|
||||
|
||||
m = __import__(module)
|
||||
suite = TestSuite()
|
||||
for c in test_cases(m):
|
||||
suite.addTest(c)
|
||||
runner = TestRunner()
|
||||
result = runner.run(suite)
|
||||
# Terminate with non zero return code in case of failures
|
||||
sys.exit(result.failuresNum > 0)
|
||||
Reference in New Issue
Block a user