2016-10-05 20 views
3

ユニットテストを実行するインポートされたモジュールから関数を呼び出すことで、学生が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>**') 

は、ここに私のcheck_testモジュールです

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は、私はcheck_add_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頭痛を引き起こしていますこれは、if句の中でさえ、nの割り当てのためです。これは、ノートブックが必要なときにグローバルスコープでnをピックアップするのを止めているようです。

疑問を避けるため、add_nにはが引数として渡されることは望ましくありません。このようなオブジェクトは多く使用されますが、テスト対象の関数によって変更されることはありません。外側のスコープで解決したいと思います。 。

どのようにすればいいですか?

+0

私はあなたの質問に答えながら、私は 'add_n'関数がかなり醜いことがわかりました。私は、 'def make_adder(n):return lambda val:val + n'と' add_n = make_adder(n) 'のような関数を書くようにして、' n'をローカルにしておきます。 – Bakuriu

+0

答え - これは大きな助けです。しかし、あなたが提案するより高度なコードが初心者として理解しやすいとは思えません。 – xnx

答えて

2

あなたは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出力を提供します。


これは、ファイルが__main__モジュールとしてsys.modulesに保存されているPythonのファイルを実行したときので、動作します。これは、なぜif __name__ == '__main__':イディオムが使用されるのかということです。そのようなモジュールをインポートすることは可能であり、既にモジュールキャッシュ内にあるので、それを再実行することはありません。

関連する問題