Python 3-具有模拟功能的多个输入和打印语句的单元测试 [英] Python 3 - Unittest with multiple inputs and print statement using mocking

查看:123
本文介绍了Python 3-具有模拟功能的多个输入和打印语句的单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究Python,几周前我创建了一个游戏,用户需要猜测用户自己定义的时间间隔之间的数字.现在,我正在学习有关单元测试的知识,我决定为该游戏编写一个测试模块.但是,由于需要用户输入4次(其中两个定义了将生成随机数的范围,一个是用户的猜测,最后一个是用户要确定是否要输入的是/否问题)继续.

I'm studying Python and a few weeks ago I had created a game which the user needs to guess the number between an interval defined by the user himself. Now that I'm learning about Unittest, I decided to write a test module for the game. However, as it takes 4 inputs from the user (two of them defines the range which the random number will be generated, one is the user's guess and the last is an Y/N question for the user to decide whether or not he wants to continue.

import random

def main():

    print('Welcome to the guess game!')

    while True:
        try:

            low_param = int(input('Please enter the lower number: '))
            high_param = int(input('Please enter the higher number: ')) 

            if high_param <= low_param:
                print('No, first the lower number, then the higher number!')

            else:
                break

        except:
            print('You need to enter a number!')


    while True:
        try:
            result = random.randint(low_param, high_param)
            guess = int(input(f'Please enter a number between {low_param} and {high_param}: '))

            if low_param <= guess <= high_param:
                if result == guess:
                    print('Nice, dude!')
                    break

                else:
                    print ('Not yet, chap')

                while True:
                    try_again = input('Would you like to try again? (Y/N) ')

                    if try_again.lower() == 'n':
                        break

                    elif try_again.lower() == 'y':
                        print('If you consider yourself capable...')
                        break

                    else:
                        pass

                if try_again.lower() == 'n':
                    print('Ok, maybe next time, pal :v')
                    break                
            else:
                print(f'Your guess must be between {low_param} and {high_param}')

        except:
            print('Are you sure you entered a number?')


if __name__ == '__main__':
    main()

在测试中,我想创建一些方法来验证以下情况:

On the tests, I want to create some methods to verify the following situations:

1-low_param或high_param不是数字 2-low_param高于high_param 3-猜测高于high_param 4-猜测低于low_param 5-猜是一个字符串 6-try_again既不是Y也不是N

1 - low_param or high_param aren't numbers 2 - low_param is higher than high_param 3 - guess is higher than high_param 4 - guess is lower than low_param 5 - guess is a string 6 - try_again is neither Y nor N

我设法在第一种方法上模拟了一个输入,但是我不知道如何使用print语句作为情境输出进行断言. 在其他情况下,我需要模拟一个以上的输入,然后就被卡住了.

I managed to mock one input on the first method, however I don't know how to assert with a print statement as the situation output. For the other situations I need to mock more than one input, and there I got stuck.

我该如何解决这两个问题?

How can I solve those two problems?

import unittest
from unittest.mock import patch
from randomgame import main

class TestRandom(unittest.TestCase):


    @patch('randomgame.input', create = True)
    def test_params_input_1(self, mock_input):

        mock_input.side_effect = ['foo']
        result = main()

        self.assertEqual(result, 'You need to enter a number!')

    @patch('randomgame.input2', create = True)
    def test_params_input_2(self, mock_inputs_2):

        mock_inputs_2.side_effect = [1 , 0]
        result = main()

        self.assertEqual(result, 'No, first the lower number, then the higher number!')



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

推荐答案

您的第一个问题是摆脱循环.您可以通过在模拟的print函数中添加一个引发异常的副作用,并在测试中忽略该异常来执行此操作.模拟的print也可以用于检查打印的消息:

Your first problem is to get out of the loop. You can do this by adding a side effect to the mocked print function that raises an exception, and ignore that exception in the test. The mocked print can also be used to check for the printed message:

@patch('randomgame.print')
@patch('randomgame.input', create=True)
def test_params_input_1(self, mock_input, mock_print):
    mock_input.side_effect = ['foo']
    mock_print.side_effect = [None, Exception("Break the loop")]
    with self.assertRaises(Exception):
        main()
    mock_print.assert_called_with('You need to enter a number!')

请注意,您必须在 second print调用中添加副作用,因为第一个用于发布欢迎消息.

Note that you have to add the side effect to the second print call, as the first one is used for issuing the welcome message.

第二个测试将完全相同(如果以相同的方式编写),但是有一个问题:在您的代码中,您捕获了泛型而不是特定的异常,因此您的"break"异常也将被捕获.通常,这是一种不好的做法,因此最好不要抓住这种特殊情况,如果转换为int失败,则会引起这种情况:

The second test would work exactly the same (if written the same way), but for one problem: in your code you catch a generic instead of a specific exception, so that your "break" exception will also be caught. This is generally bad practice, so instead of working around this it is better to catch the specific excpetion that is raised if the conversion to int fails:

while True:
    try:
        low_param = int(input('Please enter the lower number: '))
        high_param = int(input('Please enter the higher number: '))
        if high_param <= low_param:
            print('No, first the lower number, then the higher number!')
        else:
            break
    except ValueError:  # catch a specific exception
        print('You need to enter a number!')

代码中的第二个try/catch块也是如此.

The same is true for the second try/catch block in your code.

这篇关于Python 3-具有模拟功能的多个输入和打印语句的单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆