Исходный код Python повторно поднял исключение [дубликат]

Я отправляю этот ответ, потому что мой интерфейс администратора Virtualmin / Webmin решил, что было бы неплохо отключить мой PHP-движок. Я нашел время, чтобы найти решение, поэтому я решил поделиться с ним вы, ребята:

Также не забудьте проверить, что ни один из ваших конфигурационных файлов вашего сайта, связанных с этим конкретным хостом или виртуальным хостом, не имеет в них php_admin_value, которые отключают PHP, например:

php_admin_value engine Off

В случае сомнений прокомментируйте это ...

# php_admin_value engine Off

И перезагрузите свой веб-сервер.

527
задан Aaron Hall 29 January 2015 в 21:00
поделиться

11 ответов

Ваш код должен следовать этому шаблону (это тест стиля модуля unittest):

def test_afunction_throws_exception(self):
    try:
        afunction()
    except ExpectedException:
        pass
    except Exception as e:
       self.fail('Unexpected exception raised:', e)
    else:
       self.fail('ExpectedException not raised')

В Python & lt; 2.7 эта конструкция полезна для проверки определенных значений в ожидаемом исключении. Функция unittest assertRaises проверяет, было ли возбуждено исключение.

433
ответ дан Robert Siemer 20 August 2018 в 21:14
поделиться
  • 1
    и метод self.fail принимает только один аргумент – mdob 14 October 2012 в 22:54
  • 2
    Это кажется слишком сложным для тестирования, если функция генерирует исключение. Поскольку любое исключение, кроме этого исключения, будет ошибочно проверять, а не бросать исключение, не даст результата, похоже, единственное отличие состоит в том, что если вы получите другое исключение с assertRaises, вы получите ERROR вместо FAIL. – unflores 21 January 2015 в 13:52
  • 3
    есть ли способ сделать противоположное этому? Как это происходит, только если функция действительно генерирует исключение? – BUInvent 26 July 2017 в 19:44
  • 4
    @BUInvent, да, есть: stackoverflow.com/a/4319870/3405140 – moertel 27 July 2017 в 16:23
  • 5
    Обратите внимание, что для передачи аргументов в myfunc вам нужно добавить их в качестве аргументов в вызов assertRaises. См. Ответ Дэрила Спитцера. – cbron 21 February 2018 в 17:43
456
ответ дан Robert Siemer 31 October 2018 в 16:13
поделиться

Начиная с Python 2.7 вы можете использовать диспетчер контекста, чтобы получить доступ к фактическому объекту Exception:

import unittest

def broken_function():
    raise Exception('This is broken')

class MyTestCase(unittest.TestCase):
    def test(self):
        with self.assertRaises(Exception) as context:
            broken_function()

        self.assertTrue('This is broken' in context.exception)

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

http://docs.python.org/dev/library/unittest. html # unittest.TestCase.assertRaises


В Python 3.5 вы должны обернуть context.exception в str, иначе вы получите TypeError

self.assertTrue('This is broken' in str(context.exception))
312
ответ дан Art 20 August 2018 в 21:14
поделиться
  • 1
    Я использую Python 2.7.10, и выше не работает; context.exception не дает сообщения; это тип. – LateCoder 25 February 2016 в 17:55
  • 2
    Также в Python 2.7 (по крайней мере, в моем 2.7.6), используя import unittest2, вам нужно использовать str(), т. Е. self.assertTrue('This is broken' in str(context.exception)). – Sohail Si 19 January 2017 в 02:00
  • 3
    Две вещи: 1. Вы можете использовать assertIn вместо assertTrue. Например. self.assertIn («Это нарушено», context.exception) 2. В моем случае, используя 2.7.10, context.exception представляется массивом символов. Использование str не работает. Я закончил это: «.join (context.exception) Итак, собрал: self.assertIn (« Это сломан »,« .join (context.exception)) – blockcipher 7 February 2017 в 15:38
  • 4
    Нормально ли, что ваш метод забивает тестовую консоль с помощью Traceback исключения? Как я могу предотвратить это? – MadPhysicist 15 March 2017 в 15:10
  • 5
    позже я нашел другой способ получить сообщение как str исключения, это err = context.exception.message. А затем можно использовать также self.assertEqual (err, 'This is broken'), чтобы выполнить тест. – zhihong 11 May 2017 в 11:04

Вы можете использовать assertRaises из модуля unittest

import unittest

class TestClass():
  def raises_exception(self):
    raise Exception("test")

class MyTestCase(unittest.TestCase):
  def test_if_method_raises_correct_exception(self):
    test_class = TestClass()
    # note that you dont use () when passing the method to assertRaises
    self.assertRaises(Exception, test_class.raises_exception)
1
ответ дан Bruno Carvalho 20 August 2018 в 21:14
поделиться

Код в моем предыдущем ответе можно упростить до:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction)

И если afunction принимает аргументы, просто передайте их в assertRaises следующим образом:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction, arg1, arg2)
201
ответ дан Chris Seymour 20 August 2018 в 21:14
поделиться
  • 1
    Второй отрезанный о том, что делать, когда аргумент передан, был действительно полезен. – Sabyasachi 19 June 2018 в 08:07
  • 2
    – Minh Tran 24 August 2018 в 15:31

Как вы проверяете, что функция Python генерирует исключение?

Как написать тест, который выходит из строя, только если функция не генерирует ожидаемое исключение?

< / blockquote>

Short Answer:

Использовать метод self.assertRaises в качестве менеджера контекста:

    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'

Демонстрация

довольно легко продемонстрировать в оболочке Python.

Библиотека unittest

В Python 2.7 или 3:

import unittest

В Python 2.6 вы можете установить backport из 2.7's unittest, называемой unittest2 , и просто псевдоним, который как unittest:

import unittest2 as unittest

Примеры тестов

Теперь вставьте в свою оболочку Python следующую тест безопасности типа Python:

class MyTestCase(unittest.TestCase):
    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'
    def test_2_cannot_add_int_and_str(self):
        import operator
        self.assertRaises(TypeError, operator.add, 1, '1')

В тестовом режиме в качестве менеджера контекста используется assertRaises, который гарантирует, что ошибка будет правильно захвачена и очищена, при записи.

Мы могли бы также написать без менеджера контекста, см. тест два. Первым аргументом будет тип ошибки, которую вы ожидаете поднять, второй аргумент, тестируемая функция, а остальные аргументы args и ключевого слова будут переданы этой функции.

Я думаю, что это гораздо проще, легко читаемо и поддерживается только для использования диспетчера контекстов.

Запуск тестов

Для запуска тестов:

unittest.main(exit=False)

В Python 2.6 вам, вероятно, понадобится следующее :

unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))

И ваш терминал должен вывести следующее:

..
----------------------------------------------------------------------
Ran 2 tests in 0.007s

OK
<unittest2.runner.TextTestResult run=2 errors=0 failures=0>

И мы видим, что, как мы ожидаем, попытка добавить 1 и '1' приведет к TypeError.


Для получения более подробного вывода попробуйте следующее:

unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))
88
ответ дан Community 20 August 2018 в 21:14
поделиться

Я только что обнаружил, что библиотека Mock предоставляет метод assertRaisesWithMessage () (в подклассе unittest.TestCase), который будет проверять не только то, что ожидаемое исключение будет поднято, но и что оно поднято с ожидаемым сообщением:

from testcase import TestCase

import mymod

class MyTestCase(TestCase):
    def test1(self):
        self.assertRaisesWithMessage(SomeCoolException,
                                     'expected message',
                                     mymod.myfunc)
5
ответ дан Daryl Spitzer 20 August 2018 в 21:14
поделиться

from: http://www.lengrand.fr/2011/12/pythonunittest-assertraises-raises-error/

Во-первых, вот соответствующая (все еще dum : p) в файле dum_function.py:

def square_value(a):
   """
   Returns the square value of a.
   """
   try:
       out = a*a
   except TypeError:
       raise TypeError("Input should be a string:")

   return out

Вот тест, который нужно выполнить (только этот тест вставлен):

import dum_function as df # import function module
import unittest
class Test(unittest.TestCase):
   """
      The class inherits from unittest
      """
   def setUp(self):
       """
       This method is called before each test
       """
       self.false_int = "A"

   def tearDown(self):
       """
       This method is called after each test
       """
       pass
      #---
         ## TESTS
   def test_square_value(self):
       # assertRaises(excClass, callableObj) prototype
       self.assertRaises(TypeError, df.square_value(self.false_int))

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

Теперь мы готовы проверьте нашу функцию! Вот что происходит при попытке выполнить тест:

======================================================================
ERROR: test_square_value (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_dum_function.py", line 22, in test_square_value
    self.assertRaises(TypeError, df.square_value(self.false_int))
  File "/home/jlengrand/Desktop/function.py", line 8, in square_value
    raise TypeError("Input should be a string:")
TypeError: Input should be a string:

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)

ТипError активирован и генерирует ошибку теста. Проблема в том, что это именно то, что мы хотели: s.

Чтобы избежать этой ошибки, просто запустите функцию, используя лямбда в тестовом вызове:

self.assertRaises(TypeError, lambda: df.square_value(self.false_int))

Конечный вывод :

----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Отлично!

... и для меня тоже отлично!

Thansk много г-н Жюльен Ленгранд-Ламберт

12
ответ дан macm 20 August 2018 в 21:14
поделиться
  • 1
    Просто заметьте, вам не нужна лямбда. Строка self.assertRaises(TypeError, df.square_value(self.false_int)) вызывает метод и возвращает результат. Вы хотите передать метод и любые аргументы и позволить unittest называть его: self.assertRaises(TypeError, df.square_value, self.false_int) – Roman Kutlak 8 August 2013 в 13:36

Я использую doctest [1] почти везде, потому что мне нравится тот факт, что я документирую и тестирую свои функции одновременно.

Посмотрите на этот код:

def throw_up(something, gowrong=False):
    """
    >>> throw_up('Fish n Chips')
    Traceback (most recent call last):
    ...
    Exception: Fish n Chips

    >>> throw_up('Fish n Chips', gowrong=True)
    'I feel fine!'
    """
    if gowrong:
        return "I feel fine!"
    raise Exception(something)

if __name__ == '__main__':
    import doctest
    doctest.testmod()

Если вы помещаете этот пример в модуль и запускаете его из командной строки, оба тестовых примера оцениваются и проверяются.

[1] Документация на Python: 23.2 doctest - Тестирование интерактивных примеров Python

8
ответ дан pi. 20 August 2018 в 21:14
поделиться
  • 1
    Я люблю доктрину, но я считаю ее дополнением, а не заменой unittest. – TimothyAWiseman 5 October 2012 в 22:17
  • 2
    Является ли учение менее вероятным, чтобы играть хорошо с автоматическим рефакторингом? Я полагаю, что инструмент рефакторинга, предназначенный для python , должен знать о docstrings. Может кто-нибудь прокомментировать их опыт? – kdbanman 15 June 2015 в 16:37

Вы можете создать свой собственный contextmanager, чтобы проверить, было ли возбуждено исключение.

import contextlib

@contextlib.contextmanager
def raises(exception):
    try:
        yield 
    except exception as e:
        assert True
    else:
        assert False

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

with raises(Exception):
    print "Hola"  # Calls assert False

with raises(Exception):
    raise Exception  # Calls assert True

Если вы используете pytest, эта вещь уже реализована. Вы можете сделать pytest.raises(Exception):

Пример:

def test_div_zero():
    with pytest.raises(ZeroDivisionError):
        1/0

И результат:

pigueiras@pigueiras$ py.test
================= test session starts =================
platform linux2 -- Python 2.6.6 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python
collected 1 items 

tests/test_div_zero.py:6: test_div_zero PASSED
5
ответ дан Pigueiras 20 August 2018 в 21:14
поделиться

Посмотрите на метод assertRaises модуля unittest.

7
ответ дан unflores 20 August 2018 в 21:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: