Python 测试学生';用Jupyter编写带有unittest的代码

Python 测试学生';用Jupyter编写带有unittest的代码,python,unit-testing,python-3.x,jupyter-notebook,Python,Unit Testing,Python 3.x,Jupyter Notebook,我希望我的学生能够通过调用运行unittest的导入模块中的函数来检查他们在Jupyter笔记本中编写的代码。除非需要对照笔记本全局范围内要拾取的对象检查函数,否则此操作正常 这是我的检查测试模块: import unittest from IPython.display import Markdown, display def printmd(string): display(Markdown(string)) class Tests(unittest.TestCase):

我希望我的学生能够通过调用运行unittest的导入模块中的函数来检查他们在Jupyter笔记本中编写的代码。除非需要对照笔记本全局范围内要拾取的对象检查函数,否则此操作正常

这是我的
检查测试
模块:

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>**')
这里的错误并不奇怪:
add\u n
不知道我在
check\u add\u n
中定义的
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
子句中也是如此:这显然阻止了笔记本在需要时在全局范围内拾取
n

为免生疑问,我不想坚持将
n
作为参数传递给
add\u n
:可能会使用许多这样的对象,但被测试的函数不会改变它们,我希望它们在外部范围内得到解决


有什么想法吗?

您可以
导入\uuuuu main\uuuuu
访问笔记本电脑范围:

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>**')
导入单元测试
从IPython.display导入标记,显示
导入主__
def printmd(字符串):
显示(标记(字符串))
类测试(unittest.TestCase):
def检查_添加_2(自身,添加_2):
val=5
自我评估资格(添加2(val),7)
def检查添加(自身,添加):
__主要参数n=6
val=5
自我评估资格(添加(val),11)
检查=测试()
def运行检查(检查名称,func,提示=False):
尝试:
getattr(check,check_name)(func)
除了check.failureException作为e:
printmd(“**失败**”)
如果提示:
打印('提示:',e)
返回
printmd(“**通过**”)
这给了我一个通过的
输出



这是因为当您执行python文件时,该文件存储在
sys.modules
中,作为
\uuuuu主模块。这正是为什么要使用
if uuuuu name_uuuuu=='\uuuuu main\uuuuuuu':
惯用语的原因。可以导入这样的模块,因为它已经在模块缓存中,所以不会重新执行它或任何东西。

当我回答您的问题时,我发现
添加\n
函数非常难看。我希望让学生编写一个函数,比如
def make_adder(n):返回lambda val:val+n
,然后
add_n=make_adder(n)
,并将其保持在
n
本地……感谢您的回答——这是一个很大的帮助。但是,我不确定您建议的更高级的代码对于初学者来说是否容易理解。
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>**')