5

私はPythonを使用したプログラミングクラスの初心者の採点者です。私のpython-fuはそれほど強力ではありませんが、グレーディングの一部を自動化してみたいと思います。

オンラインで見ると、私はPyUnitテストスイートが好きですが、おそらく私が望むものには少し圧倒されています。

私の問題は、学生の関数に必要なテスト入力を渡す方法がわからないことです。これは、学生がコマンドライン引数や複数の関数をまだ使用していないためですが、input()関数を介してユーザー入力を取得しているためです。

ばかげた例:

#/usr/bin/python3.1
# A silly example python program
def main():
    a = int(input("Enter an integer: "))
    b = int(input("Enter another integer: "))
    c = a+b
    print("The sum is %d" % c)

if __name__ == '__main__'
    main()

私のばかげた例では、いくつかの異なる入力の出力をチェックできる単体テストをどのように作成しますか?(つまり、2と3を入力に渡すと、出力文字列は「合計は5」になります)

4

8 に答える 8

8

編集:例は単体テスト可能ではないため、これを提案するだけです(そして、初心者の学生は制約によって混乱するだけだと思います)

探しているものと一致する出力だけに関心がある場合は、「ばかげた」bashを使用してみませんか?何かのようなもの:

echo -e "2\n3" | python test.py | grep -q "The sum is 5" && echo "Success"

このような比較的些細なプログラムを実行している場合、これはほとんど労力を必要としない十分な、または十分に優れたソリューションであるはずです。

于 2011-02-01T16:39:16.267 に答える
4

それを実際に単体テストすることはできません。単体テストを作成することの1つは、単体テストを実行できるようにするために、コードを別の方法で作成する必要がある場合が多いことです。したがって、この場合、別の関数に入力するための呼び出しを除外する必要があります。その後、パッチを適用できます。

def my_input(prompt):
    return input(prompt)

def main():
    a = int(eval(my_input("Enter an integer: "))

これで、テストでモンキーパッチを適用myscript.my_inputして必要な値を返すことができます。

于 2011-02-01T16:39:57.000 に答える
2

私の提案は、Pythonが単体テスト用に提供する2つのフレームワーク(unittest(別名PyUnit)とdoctest のいずれかを使用してコードをリファクタリングすることです。

これはunittestを使用した例です:

import unittest

def adder(a, b):
    "Return the sum of two numbers as int"
    return int(a) + int(b)

class TestAdder(unittest.TestCase):
    "Testing adder() with two int"
    def test_adder_int(self):
        self.assertEqual(adder(2,3), 5)

    "Testing adder() with two float"
    def test_adder_float(self):
        self.assertEqual(adder(2.0, 3.0), 5)

    "Testing adder() with two str - lucky case"
    def test_adder_str_lucky(self):
        self.assertEqual(adder('4', '1'), 5)

    "Testing adder() with two str"
    def test_adder_str(self):
        self.assertRaises(ValueError, adder, 'x', 'y')

if __name__ == '__main__':
    unittest.main()

そしてこれはdoctestを使用した例です:

# adder.py

def main(a, b):
    """This program calculate the sum of two numbers. 
    It prints an int (see %d in print())

    >>> main(2, 3)
    The sum is 5

    >>> main(3, 2)
    The sum is 5

    >>> main(2.0, 3)
    The sum is 5

    >>> main(2.0, 3.0)
    The sum is 5

    >>> main('2', '3')
    Traceback (most recent call last):
        ...
    TypeError: %d format: a number is required, not str
    """
    c = a + b
    print("The sum is %d" % c)

def _test():
    import doctest, adder
    return doctest.testmod(adder)

if __name__ == '__main__':
    _test()

doctestで、input()を使用して別の例を作成しました(Python 3.Xを使用していると想定しています)。

# adder_ugly.py

def main():
    """This program calculate the sum of two numbers.
    It prints an int (see %d in print())

    >>> main()
    The sum is 5
    """
    a = int(input("Enter an integer: "))
    b = int(input("Enter another integer: "))
    c = a+b
    print("The sum is %d" % c)


def _test():
    import doctest, adder_ugly
    return doctest.testmod(adder_ugly)

if __name__ == '__main__':
    _test()

上記の各例を-vオプションで実行します。

python adder_ugly.py -v

参考までに、以下を参照してください。

http://docs.python.org/py3k/library/unittest.html?highlight=unittest#unittest

http://docs.python.org/py3k/library/doctest.html#module-doctest

于 2011-02-28T14:30:21.413 に答える
2

簡単に言えば、そうしないでください。テスト容易性のために設計する必要があります。これは、システムリソースとの通信に使用するインターフェイスを提供する簡単な方法を提供することを意味します。これにより、テスト時にこれらのインターフェイスの代替実装を提供できます。

他の回答で説明されているモンキーパッチソリューションは機能しますが、これはオプションの中で最も原始的です。個人的には、ユーザーとの対話のためのインターフェイスクラスを作成します。例えば:

class UserInteraction(object):
    def get_input(self):
        raise NotImplementedError()
    def send_output(self, output):
        raise NotImplementedError()

次に、ユーザーと話す必要があるものは、コンストラクターまたは関数の引数としてクラスのインスタンスを取得できます。デフォルトの実装では、実際のinput関数などを呼び出すことができますが、テストに使用されるバージョンがあり、サンプル入力を提供するか、出力をバッファリングしてチェックできるようにします。

ちなみに、これが私がシングルトンを嫌う理由です(とにかくPythonで効果的に実装することはできません)。テスト用のスタブバージョンでスタブアウトできないグローバルにアクセス可能なインスタンスを作成することにより、テストの機能が破壊されます。

于 2011-02-01T16:52:57.137 に答える
2

ドキュメントから:

オブジェクトsys.stdin、sys.stdout、およびsys.stderrは、インタプリタの標準入力、出力、およびエラーストリームに対応するファイルオブジェクトに初期化されます。

したがって、このロジックに従うと、このようなものが機能するようです。必要な入力を使用してファイルを作成します。

$ cat sample_stdin.txt
hello
world

sys.stdin次に、そのファイルを指すようにリダイレクトします。

#!/usr/bin/env python
import sys

fh = open('sample_stdin.txt', 'r')
sys.stdin = fh

line1 = raw_input('foo: ')
line2 = raw_input('bar: ')

print line1
print line2

出力:

$python redirecting_stdin.py
foo: bar: hello
world
于 2011-02-01T16:51:52.907 に答える
2

コマンドラインプログラムで提供できるよりも複雑な対話が必要な場合は、echoを参照してくださいexpect

于 2011-02-01T16:46:40.187 に答える
0

inputテスト環境から入力を提供する関数をモックできる場合があります。

これはうまくいくようです。テストされていません。

class MockInput( object ):
    def __init__( self, *values ):
        self.values= list(values)
        self.history= []
    def __call__( self, *args, **kw ):
        try:
            response= self.values.pop(0)
            self.history.append( (args, kw, response) )
            return response
        except IndexError:
            raise EOFError()

class TestSomething( unittest.TestCase ):
    def test_when_input_invalid( self ):
        input= MockInput( "this", "and", "that" )
        # some test case based on the input function
于 2011-02-01T16:57:55.727 に答える
0

sys.stdinをStringIO(またはcStringIO)オブジェクトに置き換えます。

于 2011-02-02T04:51:29.860 に答える