2016-03-19 39 views
2

Ich schrieb einen Unittest Timeout zu testen, mit dem Paket-AnfragenPython Requests Mock verfängt nicht Ausnahme Timeout

my_module.py:

import requests 

class MyException(Exception): pass 

def my_method(): 
    try: 
     r = requests.get(...) 
    except requests.exceptions.Timeout: 
     raise MyException() 

Unittest:

from mock import patch 
from unittest import TestCase 
from requests.exceptions import Timeout 

from my_module import MyException 

@patch('my_module.requests') 
class MyUnitTest(TestCase): 
    def my_test(self, requests): 
     def get(*args, **kwargs): 
      raise Timeout() 

     requests.get = get 

     try: 
      my_module.my_method(...) 
     except MyException: 
      return 

     self.fail("No Timeout) 

Aber wenn es Läuft, der Versuch Block in my_method fängt nie die requests.exceptions.Timeout

Antwort

2

Es gibt zwei Probleme, die ich hier zu sehen. Einer, der Ihr Problem direkt behebt, und der zweite ist ein leichter Missbrauch des Mocking-Frameworks, der Ihre Implementierung weiter vereinfacht.

Erstens, um direkt Ihr Problem zu beheben, je nachdem, wie Sie schauen, um Ihre Behauptung zu testen, was Sie suchen hier eigentlich tun:

requests.get = get 

Sie sollte eine side_effect hier verwendet werden, um zu helfen Erhebe deine Ausnahme. Per die documentation:

side_effect allows you to perform side effects, including raising an exception when a mock is called

Mit dem im Verstand, alle müssen Sie dies wirklich tun:

requests.get.side_effect = get 

Das Exception bekommen sollte zu erhöhen. Allerdings stehen die Chancen, Sie Macht Gesicht dieser Fehler:

TypeError: catching classes that do not inherit from BaseException is not allowed 

Dies kann besten erklärt eigentlich Lesen this große Antwort, warum das geschieht. Mit dieser Antwort wird es Ihnen helfen, Ihr Problem vollständig zu lösen, indem Sie diesen Vorschlag dazu verwenden, nur das auszuprobieren, was Sie benötigen. benötigen Sie. Also, am Ende, wird Ihr Code tatsächlich in etwa so aussehen, mit dem verspotteten get statt verspottet requests Modul:

class MyUnitTest(unittest.TestCase): 

    @patch('my_module.requests.get') 
    def test_my_test(self, m_get): 
     def get(*args, **kwargs): 
      raise Timeout() 

     m_get.side_effect = get 

     try: 
      my_method() 
     except MyException: 
      return 

Sie können nun tatsächlich dies weiter vereinfachen, indem sie eine bessere Nutzung zu machen, was in Unittest mit assertRaises anstelle des try/except. Dies wird letztendlich nur bestätigen, dass die Ausnahme ausgelöst wurde, als die Methode aufgerufen wurde. Außerdem brauchen Sie nicht brauchen, um eine neue Methode zu erstellen, die eine Zeitüberschreitung auslösen wird, können Sie einfach angeben, dass Ihre verspotteten erhalten eine side_effect, die eine Ausnahme auslöst.So können Sie das gesamte def get mit einfach diese ersetzen:

m_get.side_effect = Timeout() 

Sie können jedoch tatsächlich diese direkt in Ihrem Patch Dekorateur setzen, so, jetzt Ihre endgültige Code wird wie folgt aussehen:

class MyUnitTest(unittest.TestCase): 

    @patch('my_module.requests.get', side_effect=Timeout()) 
    def test_my_test(self, m_get):  
     with self.assertRaises(MyException): 
      my_method() 

Ich hoffe das hilft!

0

patch('my_module.requests') ersetzt my_module.requests durch ein neues Mock-Objekt, aber in Ihrer Testmethode ersetzen Sie die Methode requests.get des direkt importierten und daher auf dem ursprünglichen Anfrage-Modul, was bedeutet, dass die Änderung nicht in Ihrem Modul widergespiegelt wird.

Es sollte funktionieren, wenn in der Testmethode, die Sie auf der Anfragen Mock in Ihrem my_module statt ersetzen:

my_module.requests.get = get