How to test Python programs for novice students who use input () (perhaps with unittest?)?

I am a grader for a beginner programming class using Python. My python-fu is not very strong myself, but I would like to try to automate some evaluations.

In online mode, I like PyUnit , although it is probably a bit depressed for what I want.

My problem is that I'm not sure how to pass the test inputs that I want to run to students, because they do not use command line arguments or even several functions, but receive user input through a function input().

Silly example:

#/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()

, unit test, ? (.. 2 3 , " 5" )

+5
8

: , unittest- ( , - )

, , , "" bash? - :

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

, , , .

+8

. - -, . , , .

def my_input(prompt):
    return input(prompt)

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

... myscript.my_input, .

+4

, echo, expect.

+2

docs:

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
+2

, . . , .

, , , . . :

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

, , . input - , , , , .

, , Singleton ( Python). , , , .

+2

, , Python : unittest (aka 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

+2

You can fake a function inputto input inputs from the test environment.

It seems like this might work. It is not verified.

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
0
source

Replace sys.stdin with a StringIO (or cStringIO) object.

0
source

All Articles