Python Forum
unit test roll die - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: unit test roll die (/thread-13903.html)



unit test roll die - saladgg - Nov-06-2018

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



RE: unit test roll die - woooee - Nov-06-2018

Your second print is a different randint from the first one.


RE: unit test roll die - stullis - Nov-06-2018

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.


RE: unit test roll die - saladgg - Nov-06-2018

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 Smile

I just resolved a test on bubble sort algorithm, I am now trying merge sort.


RE: unit test roll die - saladgg - Nov-06-2018

(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}"



RE: unit test roll die - stullis - Nov-06-2018

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.