Skip to content

Unittest updates from pycopy #487

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 37 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
86dd99a
unittest: Allow passing module name or instance into unittest.main()
andrewleech Nov 1, 2018
96007cf
unittest: Log failure tracebacks at test end.
andrewleech Oct 31, 2018
209da35
unittest: Release 0.4.
pfalcon Nov 3, 2018
81e6b6e
unittest: test_unittest.py: Fix typo in method name.
pfalcon Dec 18, 2018
d098bc6
unittest: Allow to catch AssertionError with assertRaises().
Oct 31, 2018
0f495df
unittest: test_unittest: Add test for .assertRaises(AssertionError).
pfalcon Jan 25, 2019
c2c761a
unittest: Release 0.4.1.
pfalcon Jan 25, 2019
6d9ab14
unittest: test_unittest: Typo fix.
pfalcon Mar 3, 2019
2113897
unittest: AssertRaisesContext: Store exception value as self.exception.
pfalcon Jul 27, 2019
bb06989
unittest: Release 0.4.2.
pfalcon Jul 27, 2019
e6d950e
unittest: Add assertLessEqual, assertGreaterEqual methods.
pfalcon Aug 13, 2019
9a8d644
unittest: Release 0.4.3.
pfalcon Aug 13, 2019
74f6b45
unittest: Reinstate useful debugger helper.
pfalcon Dec 14, 2019
06ee16e
unittest: TestSuite: Add undescore to internal field, self._tests.
pfalcon Dec 15, 2019
1629f67
unittest: Only treat callable fields as test methods.
pfalcon Dec 15, 2019
9f72618
unittest: Release 0.4.4.
pfalcon Dec 15, 2019
096beea
unittest: Support both test classes and class instances.
pfalcon Feb 26, 2020
de45d34
unittest: TestCase: Add (dummy) __init__.
pfalcon Feb 27, 2020
375ad10
unittest: Release 0.5.
pfalcon Feb 28, 2020
73238f6
unittest: Add TestCase.skipTest() method.
pfalcon Aug 8, 2020
5a8b3fe
unittest: Add dummy TestCase.subTest() context manager.
pfalcon Aug 9, 2020
cd0e67f
unittest: Add dummy TestCase.assertWarns() context manager.
pfalcon Aug 10, 2020
68409a1
unittest: Release 0.5.1.
pfalcon Aug 11, 2020
c2d27fa
unittest: TestSuite: Add run() method.
pfalcon Nov 15, 2020
4f0e2a2
unittest: Release 0.5.2.
pfalcon Nov 16, 2020
e2ce110
unittest: Implement basic addCleanup()/doCleanup().
pfalcon May 12, 2021
8b1eed7
unittest: Properly handle failures vs errors.
pfalcon May 14, 2021
166ac71
unittest: Support recursive TestSuite's.
pfalcon May 15, 2021
6b431aa
unittest: Release 0.6.
pfalcon May 16, 2021
5e09488
unittest: Add expectedFailure decorator.
pfalcon Jul 19, 2021
8cdd3c0
unittest: test_unittest: Add tests for expectedFailure decorator.
pfalcon Jul 20, 2021
df5ef99
unittest: Release 0.6.1.
pfalcon Jul 21, 2021
0d58644
unittest: Print no. of skipped tests in a way compatible with CPython.
pfalcon Oct 12, 2021
86a5de6
unittest: Add TextTestRunner as alias for TestRunner.
pfalcon Oct 13, 2021
865bc6d
unittest: Release 0.6.2.
pfalcon Oct 14, 2021
621738b
unittest: Support TestCase subclasses with own runTest() method.
pfalcon Oct 23, 2021
f6ad093
unittest: Release 0.7.
pfalcon Oct 24, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion python-stdlib/unittest/metadata.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
srctype = micropython-lib
type = module
version = 0.3.2
version = 0.7
2 changes: 1 addition & 1 deletion python-stdlib/unittest/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

setup(
name="micropython-unittest",
version="0.3.2",
version="0.7.0",
description="unittest module for MicroPython",
long_description="This is a module reimplemented specifically for MicroPython standard library,\nwith efficient and lean design in mind. Note that this module is likely work\nin progress and likely supports just a subset of CPython's corresponding\nmodule. Please help with the development if you are interested in this\nmodule.",
url="https://github.com/micropython/micropython-lib",
Expand Down
35 changes: 33 additions & 2 deletions python-stdlib/unittest/test_unittest.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_AlmostEqual(self):
with self.assertRaises(AssertionError):
self.assertNotAlmostEqual(float("inf"), float("inf"))

def test_AmostEqualWithDelta(self):
def test_AlmostEqualWithDelta(self):
self.assertAlmostEqual(1.1, 1.0, delta=0.5)
self.assertAlmostEqual(1.0, 1.1, delta=0.5)
self.assertNotAlmostEqual(1.1, 1.0, delta=0.05)
Expand Down Expand Up @@ -109,7 +109,38 @@ def testRaises(self):

@unittest.skip("test of skipping")
def testSkip(self):
self.assertFail("this should be skipped")
self.fail("this should be skipped")

def testAssert(self):

e1 = None
try:

def func_under_test(a):
assert a > 10

self.assertRaises(AssertionError, func_under_test, 20)
except AssertionError as e:
e1 = e

if not e1 or "not raised" not in e1.args[0]:
self.fail("Expected to catch lack of AssertionError from assert in func_under_test")

@unittest.expectedFailure
def testExpectedFailure(self):
self.assertEqual(1, 0)

def testExpectedFailureNot(self):
@unittest.expectedFailure
def testInner():
self.assertEqual(1, 1)

try:
testInner()
except:
pass
else:
self.fail("Unexpected success was not detected")


if __name__ == "__main__":
Expand Down
183 changes: 157 additions & 26 deletions python-stdlib/unittest/unittest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import sys

try:
import io
import traceback
except ImportError:
import uio as io

traceback = None


class SkipTest(Exception):
pass
Expand All @@ -13,14 +21,43 @@ def __enter__(self):
return self

def __exit__(self, exc_type, exc_value, tb):
self.exception = exc_value
if exc_type is None:
assert False, "%r not raised" % self.expected
if issubclass(exc_type, self.expected):
return True
return False


class NullContext:
def __enter__(self):
pass

def __exit__(self, a, b, c):
pass


class TestCase:
def __init__(self):
pass

def addCleanup(self, func, *args, **kwargs):
if not hasattr(self, "_cleanups"):
self._cleanups = []
self._cleanups.append((func, args, kwargs))

def doCleanups(self):
if hasattr(self, "_cleanups"):
while self._cleanups:
func, args, kwargs = self._cleanups.pop()
func(*args, **kwargs)

def subTest(self, msg=None, **params):
return NullContext()

def skipTest(self, reason):
raise SkipTest(reason)

def fail(self, msg=""):
assert False, msg

Expand All @@ -34,6 +71,16 @@ def assertNotEqual(self, x, y, msg=""):
msg = "%r not expected to be equal %r" % (x, y)
assert x != y, msg

def assertLessEqual(self, x, y, msg=None):
if msg is None:
msg = "%r is expected to be <= %r" % (x, y)
assert x <= y, msg

def assertGreaterEqual(self, x, y, msg=None):
if msg is None:
msg = "%r is expected to be >= %r" % (x, y)
assert x >= y, msg

def assertAlmostEqual(self, x, y, places=None, msg="", delta=None):
if x == y:
return
Expand Down Expand Up @@ -118,12 +165,16 @@ def assertRaises(self, exc, func=None, *args, **kwargs):

try:
func(*args, **kwargs)
assert False, "%r not raised" % exc
except Exception as e:
if isinstance(e, exc):
return
raise

assert False, "%r not raised" % exc

def assertWarns(self, warn):
return NullContext()


def skip(msg):
def _decor(fun):
Expand All @@ -148,68 +199,148 @@ def skipUnless(cond, msg):
return skip(msg)


def expectedFailure(test):
def test_exp_fail(*args, **kwargs):
try:
test(*args, **kwargs)
except:
pass
else:
assert False, "unexpected success"

return test_exp_fail


class TestSuite:
def __init__(self):
self.tests = []
self._tests = []

def addTest(self, cls):
self.tests.append(cls)
self._tests.append(cls)

def run(self, result):
for c in self._tests:
run_suite(c, result)
return result


class TestRunner:
def run(self, suite):
res = TestResult()
for c in suite.tests:
run_class(c, res)
suite.run(res)

res.printErrors()
print("----------------------------------------------------------------------")
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
msg += " (skipped=%d)" % res.skippedNum
print(msg)

return res


TextTestRunner = TestRunner


class TestResult:
def __init__(self):
self.errorsNum = 0
self.failuresNum = 0
self.skippedNum = 0
self.testsRun = 0
self.errors = []
self.failures = []

def wasSuccessful(self):
return self.errorsNum == 0 and self.failuresNum == 0

def printErrors(self):
print()
self.printErrorList(self.errors)
self.printErrorList(self.failures)

def printErrorList(self, lst):
sep = "----------------------------------------------------------------------"
for c, e in lst:
print("======================================================================")
print(c)
print(sep)
print(e)

def __repr__(self):
# Format is compatible with CPython.
return "<unittest.result.TestResult run=%d errors=%d failures=%d>" % (
self.testsRun,
self.errorsNum,
self.failuresNum,
)


def capture_exc(e):
buf = io.StringIO()
if hasattr(sys, "print_exception"):
sys.print_exception(e, buf)
elif traceback is not None:
traceback.print_exception(None, e, sys.exc_info()[2], file=buf)
return buf.getvalue()


# TODO: Uncompliant
def run_class(c, test_result):
o = c()
def run_suite(c, test_result):
if isinstance(c, TestSuite):
c.run(test_result)
return

if isinstance(c, type):
o = c()
else:
o = c
set_up = getattr(o, "setUp", lambda: None)
tear_down = getattr(o, "tearDown", lambda: None)
exceptions = []

def run_one(m):
print("%s (%s) ..." % (name, c.__qualname__), end="")
set_up()
try:
test_result.testsRun += 1
m()
print(" ok")
except SkipTest as e:
print(" skipped:", e.args[0])
test_result.skippedNum += 1
except Exception as ex:
ex_str = capture_exc(ex)
if isinstance(ex, AssertionError):
test_result.failuresNum += 1
test_result.failures.append(((name, c), ex_str))
print(" FAIL")
else:
test_result.errorsNum += 1
test_result.errors.append(((name, c), ex_str))
print(" ERROR")
# Uncomment to investigate failure in detail
# raise
finally:
tear_down()
o.doCleanups()

if hasattr(o, "runTest"):
name = str(o)
run_one(o.runTest)
return

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
if not callable(m):
continue
finally:
tear_down()
run_one(m)
return exceptions


def main(module="__main__"):
Expand All @@ -219,11 +350,11 @@ def test_cases(m):
if isinstance(c, object) and isinstance(c, type) and issubclass(c, TestCase):
yield c

m = __import__(module)
m = __import__(module) if isinstance(module, str) else 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)
sys.exit(result.failuresNum or result.errorsNum)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy