Обнаружение события input() при запуске программы и сбой вызова метода

#python #automated-tests

Вопрос:

Фон

У меня есть задача запустить множество методов python против наборов тестов в пакетном режиме. Я написал программу для динамического определения методов и соответствующих тестовых примеров (с использованием exec(str) ) и автоматического запуска тестовых примеров.

Проблема

Правильный код не должен содержать input() инструкцию, которая требует ввода пользователем. Однако существует неправильный код, который может содержать input() инструкции, которые блокируют выполнение и ожидание ввода пользователем. Как я могу определить, вызывается ли an input() и моя программа зависает там? Существуют ли подходы для сбоя такого вызова метода и продолжения программы?

Краткие сведения

  • Как я могу определить, вызывается ли an input() и моя программа зависает там?
  • Существуют ли подходы для сбоя такого вызова метода и продолжения программы?

Ответ №1:

Как я могу определить, вызывается ли an input() и моя программа зависает там?

Предположим, у вас есть два метода — один правильный и один неправильный:

 class Foo:
    def correct(self, x):
        return x
        
    def incorrect(self):
        # You shouldn't use input!
        a = int(input())
        return 42   a
 

Вы можете использовать unittest.mock библиотеку. Создайте функцию, которая определяет, использовался ли какой-либо вызов input :

 import unittest.mock

def check(f, *args, **kwargs):
    # Store the real `input` function in a variable
    real_input = __builtins__.input
    
    # Use `unittest.mock` to catch any calls to this variable
    __builtins__.input = unittest.mock.MagicMock()
    
    # Call the desired function with the provided arguments
    f(*args, **kwargs)
    
    # Check if the fake `input` function was called
    result = __builtins__.input.called
    
    # Restore the value of the `input` function
    __builtins__.input = real_input

    # Return if the fake `input` function was called
    return result
 

Вы можете использовать его следующим образом:

 foo = Foo()
print(check(foo.correct, 42))    # Outputs False
print(check(foo.incorrect))      # Outputs True
 

Существуют ли подходы для сбоя такого вызова метода и продолжения программы?

Замените check функцию на

 def check(f, *args, **kwargs):
    # Use a custom error so that, if the original function throws an
    # error, it wouldn't be catch mistakenly inside the `check` function
    class _MyCustomError(BaseException):
        pass

    real_input = __builtins__.input
    
    __builtins__.input = unittest.mock.Mock(side_effect=_MyCustomError())
    
    try:
        f(*args, **kwargs)
    except _MyCustomError:
        return True
    else:
        return False
    finally:
        __builtins__.input = real_input
 

С этой модификацией использование будет:

 foo = Foo()
print(check(foo.correct, 42))    # Outputs False
print(check(foo.incorrect))      # Outputs True and fail the function with _MyCustomError