12

私は、変数と関数を非表示にしてから、リフレクションを使用してそれらに対して単体テストを実行できる Java の世界から来ました。ネストされた関数を使用してクラスの実装の詳細を非表示にし、パブリック API のみが表示されるようにしました。これらのネストされた関数に対して単体テストを作成して、開発中に壊れないようにしようとしています。次のようなネストされた関数のいずれかを呼び出してみました。

def outer():
    def inner():
        pass

outer.inner()

エラーメッセージが表示されます:

AttributeError: 'function' オブジェクトに属性 'inner' がありません

これらのネストされた関数に対して単体テストを作成する方法はありますか? そうでない場合、__ を前に付けてクラス変数の場合と同じように、関数名の名前変更をトリガーする方法はありますか?

4

7 に答える 7

17

インナーはアウターが作るまで存在しません。テスト容易性のために内部を最上位の関数に移動するか、外部テストでそれ自体と内部のすべての可能な実行パスをテストする必要があります。

内部関数は単純な関数ではなく、クロージャであることに注意してください。この場合を考えてみましょう:

def outer(a):
    b = compute_something_from(a)
    def inner():
        do_something_with(a, b)

これが、標準的な妥当性のトレードオフです。循環的複雑度が高すぎると、テストが多すぎます。

于 2008-11-28T23:44:55.140 に答える
4

Pythonの規則では、「プライベート」関数とメソッドに先頭にアンダースコアを付けて名前を付けます。先頭にアンダースコアが表示されている場合は、それを使用しないようにしてください。

PythonはJavaではないことを忘れないでください。

于 2008-11-29T00:04:42.633 に答える
3

extern 名前空間から inner() にアクセスする機会はないと思います。

ただし、私の意見では、inner() をネストしたままにしておくという事実は、本当に重要な唯一の「契約」がouter()のものであることを意味します。inner() は実装の一部であり、実装をテストする必要はありません。本当に inner() をテストしたい場合は、inner() のすべての機能を含むデータを使用して、outer() で広範なテストを行います。

于 2008-11-29T00:25:40.050 に答える
3

まさにこれを可能にする小さなヘルパー モジュールを作成しました。

ネストされた関数の例:

def f(v1):
  v2 = 1
  def g(v3=2):
    return v1 + v2 + v3 + 4
  def h():
    return 16
  return g() + h() + 32

class C(object):
  def foo(self):
    def k(x):
      return [ self, x ]
    return k(3)

def m():
  vm = 1
  def n(an=2):
    vn = 4
    def o(ao=8):
      vo = 16
      return vm + an + vn + ao + vo
    return o()
  return n()

これらは、この種のコードを使用して単体テストできます。

import unittest
from nested import nested

class TestNested(unittest.TestCase):
  def runTest(self):
    nestedG = nested(f, 'g', v1=8, v2=1)
    self.assertEqual(nestedG(2), 15)
    nestedH = nested(f, 'h')
    self.assertEqual(nestedH(), 16)
    nestedK = nested(C.foo, 'k', self='mock')
    self.assertEqual(nestedK(5), [ 'mock', 5 ])
    nestedN = nested(m, 'n', vm=1)
    nestedO = nested(nestedN, 'o', vm=1, an=2, vn=4)
    self.assertEqual(nestedO(8), 31)

def main(argv):
  unittest.main()

if __name__ == '__main__':
  import sys
  sys.exit(main(sys.argv))

小さなヘルパー モジュールnestedは次のようになります。

import types

def freeVar(val):
  def nested():
    return val
  return nested.__closure__[0]

def nested(outer, innerName, **freeVars):
  if isinstance(outer, (types.FunctionType, types.MethodType)):
    outer = outer.func_code
  for const in outer.co_consts:
    if isinstance(const, types.CodeType) and const.co_name == innerName:
      return types.FunctionType(const, globals(), None, None, tuple(
          freeVar(freeVars[name]) for name in const.co_freevars))
于 2016-11-09T17:08:25.697 に答える
2

外部関数オブジェクトから内部関数を取得する方法はありません (他の回答を参照してください!)。それでも、単体テストとクロージャの両方により、(少なくとも私にとっては) 開発者のパフォーマンスが驚くほど改善されました。両方できますか?ネストされた関数を単独でテストできますか?

簡単ではありません。

ただし、Pythonモジュールのパーサー、ast、またはトークナイザーを使用してコード自体を切り刻み、内部関数を抽出し(ネストを介したパスによって)、テストがそれらを囲む関数からの状態で実行できるようにすることで、これを達成できるようです(値閉じた名前の場合) およびよりネストされた関数のスタブ/モック (テストターゲット内で定義)。

このようなことを知っている人はいますか?グーグルは何も見つけられませんでした。

于 2011-07-09T16:12:27.737 に答える