Home > front end >  How could I use 'assert' and a variable 'actual' to write a test code for a user
How could I use 'assert' and a variable 'actual' to write a test code for a user

Time:11-30

`

def conversion():
    options = print('Would you like to convert hours to mins, or mins to hours?')
    choice = input()

    if choice == 'hours to mins':
        hours = int(input('How many hours? '))
        mins = hours * 60
        print(mins, 'Minutes')
    elif choice == 'mins to hours':
        mins = int(input('How many minutes? '))
        hours = mins/60
        print(hours, 'Hours')
    else:
        print('An error has occured')
        


conversion()

This is the production code which is meant to be used to write a corresponding test code. `

I am unsure on how to go about writing a test code using 'siminput' 'assert' and the a variable 'actual' to write a working test code for the line of code above for it to properly run in unittest.

CodePudding user response:

You can use pytest with the pytest-mock extension. Install them via pip or conda, or whatever you use.


Quick Fix

First I made a small change to your code to make it a bit easier to test: I added a return statement. Now the code will also return the result.

# conversion.py
def conversion():
    print('Would you like to convert hours to mins, or mins to hours?')
    choice = input()

    if choice == 'hours to mins':
        hours = int(input('How many hours? '))
        mins = hours * 60
        print(mins, 'Minutes')
        return mins
    elif choice == 'mins to hours':
        mins = int(input('How many minutes? '))
        hours = mins/60
        print(hours, 'Hours')
        return hours
    else:
        print('An error has occured')
        return False

Ok, now we create a test

# conversion_test.py
def test_hrs_to_min(mocker):
    input_provider = mocker.patch('builtins.input')
    # The following line is crucial: You configure the 
    # values each call to `Input` will return in order. 
    input_provider.side_effect = ['hours to mins', '3']
    result = conversion()
    assert result == 3*60

when we run this now with pytest -s from the command line, we see the expected print result and a green dot for the passed test. Try to add the other scenarios and error cases on your own (e.g. what happens if hour input is not an int)

You can also mock the builtin.print and check if it was called with the right arguments (mock_print.assert_called_with(3*60, "Minutes").

See Mocking examples for further details.


Better Solution

As already mentioned it'd be a good idea to separate concerns in your code.

def conversion():
    print('Would you like to convert hours to mins, or mins to hours?')
    choice = input()
    if choice == 'hours to mins':
        hours = int(input('How many hours? '))
        print(hrs2mins(hours), 'Minutes')
    elif choice == 'mins to hours':
        mins = int(input('How many minutes? '))
        print(min2hrs(mins), 'Hours')

    print('An error has occurred')
    return False


def hrs2mins(hrs: int) -> int:
    return hrs * 60


def min2hrs(mins: int) -> float:
    return mins/60

now you can test the "business logic" (the conversion) separately from the User interface...

CodePudding user response:

test_input.py:

def conversion():
    print("Would you like to conver...")
    choice = input()

    if choice == 'hour to mins':
        hours = int(input("How many hours?"))
        mins = hours * 60
        print(mins, "Minutes")
    else:
        print('An error has occured')

test_conversion.py:

from unittest import mock
from unittest import TestCase
from test_input import conversion
from io import StringIO


class ConversionTest(TestCase):
    @mock.patch('test_input.input', create=True)
    def test_minutes(self, mocked_input):
        mocked_input.side_effect = ["hour to mins", 4]
        with mock.patch('sys.stdout', new=StringIO()) as fake_out:
            conversion()
            output = fake_out.getvalue()
            self.assertEqual(output.replace("\n", ""), 'Would you like to conver...240 Minutes')
  • Related