我希望我的学生能够通过从运行单元测试的导入模块调用函数来检查他们在Jupyter笔记本中编写代码的代码。除非需要针对要在Notebook的全局范围内拾取的对象检查函数,否则这样可以正常工作。
这是我的check_test
模块:
import unittest
from IPython.display import Markdown, display
def printmd(string):
display(Markdown(string))
class Tests(unittest.TestCase):
def check_add_2(self, add_2):
val = 5
self.assertAlmostEqual(add_2(val), 7)
def check_add_n(self, add_n):
n = 6
val = 5
self.assertAlmostEqual(add_n(val), 11)
check = Tests()
def run_check(check_name, func, hint=False):
try:
getattr(check, check_name)(func)
except check.failureException as e:
printmd('**<span style="color: red;">FAILED</span>**')
if hint:
print('Hint:', e)
return
printmd('**<span style="color: green;">PASSED</span>**')
如果笔记本是:
In [1]: def add_2(val):
return val + 2
In [2]: def add_n(val):
return val + n
In [3]: import test_checks
In [4]: test_checks.run_check('check_add_2', add_2)
PASSED
In [5]: test_checks.run_check('check_add_n', add_n)
!!! ERROR !!!
此处的错误并不令人惊讶:add_n
不了解我在n
中定义的check_add_n
。
所以我认为我可以做类似的事情:
In [6]: def add_n(val, default_n=None):
if default_n:
n = default_n
return val + n
在笔记本中,然后在测试中传递n
:
def check_add_n(self, add_n):
val = 5
self.assertAlmostEqual(add_n(val, 6), 11)
但由于UnboundLocalError
的分配,即使在n
条款中,这也导致我if
头痛:这显然阻止笔记本电脑拿起{{1}在需要的时候在全球范围内。
为避免疑问,我不想要坚持n
作为n
的参数传递:可能有许多此类对象被使用但未被测试的函数更改我希望它们在外部范围内得到解决。
任何想法如何解决这个问题?
答案 0 :(得分:3)
您可以import __main__
访问笔记本范围:
import unittest
from IPython.display import Markdown, display
import __main__
def printmd(string):
display(Markdown(string))
class Tests(unittest.TestCase):
def check_add_2(self, add_2):
val = 5
self.assertAlmostEqual(add_2(val), 7)
def check_add_n(self, add_n):
__main__.n = 6
val = 5
self.assertAlmostEqual(add_n(val), 11)
check = Tests()
def run_check(check_name, func, hint=False):
try:
getattr(check, check_name)(func)
except check.failureException as e:
printmd('**<span style="color: red;">FAILED</span>**')
if hint:
print('Hint:', e)
return
printmd('**<span style="color: green;">PASSED</span>**')
这给了我一个PASSED
输出。
这是有效的,因为当您执行python文件时,该文件作为sys.modules
模块存储在__main__
中。这正是使用if __name__ == '__main__':
成语的原因。可以导入这样的模块,因为它已经在模块缓存中,它不会重新执行它或任何东西。