I am beginner at tests. I am trying to do a unit test for a roll die program.
I have tried many options and failed.
Here is the code:
from random import randint
def run():
try:
num = int(input('Enter an number to roll: '))
print('result: ', randint(1, 6))
while num != 0:
num = int(input('Enter an number to roll your die, 0 to quit: '))
print('result: ', randint(1, 6))
else:
return 'Game terminated!'
except ValueError:
return 'Only integers are allowed'
#run()
The program just freezes when I run the test program.
What am i doing wrong?
Here is the test part.
import pytest
import rolldie
from unittest import mock
def test_die():
with mock.patch('builtins.input', input_value=range(1, 10)):
assert rolldie.run() == range(1, 7)
with mock.patch('builtins.iput', input_value=0):
assert rolldie.run() == "Game terminated!"
with mock.patch('builtins.iput', input_value='a'):
assert rolldie.run() == "Only integers are allowed"
if __name__ == '__main__':
pytest.main()
Your second print is a different randint from the first one.
In test_die(), mock.patch() isn't being used in your with statements. When using "with", you need to assign the operation as a variable and reference that variable in the following code body. From the documentation:
with patch('__main__.Class') as MockClass:
instance = MockClass.return_value
instance.method.return_value = 'foo'
assert Class() is instance
assert Class().method() == 'foo'
In test_die on line 8, there will be an assertion error because rolldie.run() does not return a range object. Your next two assertions would work because those strings are returned by rolldie.run(). A proper test passes a known value to a function/method and validates that the returned value matches expectations.
The third problem I see is that rolldie.run() isn't supportive of testing because of the input() calls. In fact, that's likely why it's freezing; rolldie.run() isn't receiving the inputs it wants so the program cannot move forward. Unit tests are best used with functions that return a value. I rewrote the code to support unit testing though there isn't really enough there to test:
from random import randint
def run():
while True:
num = integer_input("Enter an number to roll: ")
if validate(num):
return "Game terminated"
roll = randint(1,6)
print(format_result(roll))
def integer_input(message):
while True:
try:
x = int(input(message))
return x
except ValueError:
print("\nInvalid value, please enter an integer.")
def validate(num):
return num == 0
def format_result(num):
return f"Result {num}"
With that code, you could test both validate() and format_result() because they have predictable outputs with known inputs. So, you could ensure that validate returns True if a 0 is passed in or that "Result 5" is returned by format_result is a 5 is provided. However, we already know those would work since those functions merely do basic behaviors of Python.
I know there's not much to test. It's part of test that I am taking. I am also a beginner in python, your approach has taught me new ways to write code that I didn't know before. Thanks @
stullis
I just resolved a test on bubble sort algorithm, I am now trying merge sort.
(Nov-06-2018, 11:43 AM)stullis Wrote: [ -> ]def integer_input(message):
while True:
try:
x = int(input(message))
return x
except ValueError:
print("\nInvalid value, please enter an integer.")
had easy time testing each function, am having trouble testing this one.
the other two functions just needed a line of code to be tested like;
def test_validate():
assert rolldie.validate(True) == 0
def test_result():
num = 2
assert rolldie.format_result(num) == f"Result {num}"
Testing integer_input() isn't feasible because of the input() call. As written, it will not return anything without an input value and it can't be tested without a return value. On a positive note, isolating the input into its own function lets us test the rest of the code.