2013-09-03 15 views
11

Birkaç web hizmetine arabirimler sağlayan bir paketi denemeye çalışıyorum. İnternete bağlanan olmadan çoğu fonksiyonun test edilmesi gereken bir test paketine sahiptir. Ancak, internete/indirme verilerine bağlanmayı deneyebilecek bazı testler var ve bunların iki nedenden ötürü bunları engellemesini istiyorum: birincisi, ağ bağlantım yokken test takımımın çalıştığından emin olmak için; İkincisi, bu yüzden web servislerini fazla sorgu ile spam etmiyorum.Python: Test amacıyla ağ bağlantılarını engelle?

Açık bir çözüm makinemi çıkarmak veya kablosuz bağlantıyı kapatmaktır; ancak, açık bir makinede test gerçekleştirdiğimde açıkçası çalışmıyor.

Yani, sorum şu: Tek bir python işlemi için ağ/bağlantı noktası erişimini engelleyebilir miyim? ("Kum" o, ama sadece engelleme ağ bağlantıları)

EDIT (AFAICT pysandbox bu yapmaz): Ben py.test yüzden bu durumda, py.test ile çalışacak bir çözüm gerek kullanıyorum Bu önerilen cevapları etkiler.

cevap

10

Maymun yama socket yapmalı mıyız:

import socket 
def guard(*args, **kwargs): 
    raise Exception("I told you not to use the Internet!") 
socket.socket = guard 

bu başka bir ithalat önce çalışır emin olun.

+0

Bu harika! Başka bir şeyden önce bunu çalıştırmak için nasıl py.test almak için herhangi bir düşünce? – keflavich

+0

Son yorumuma cevap ver: şunu çalıştır: 'conftests.py'. – keflavich

+0

@keflavich Bilmekte fayda var - teşekkürler! –

7

Güncelleştirme: Bu yanıtla aynı şeyi yapan bir pytest eklentisi var! Sadece işlerin nasıl görmek cevabı okuyabilir, ancak şiddetle eklentisi kullanarak yerine Buraya bakın :-) cevabımı kopyalama yapıştırmayı tavsiye : Çok olmaya Thomas Orozco'nun cevabını buldu https://github.com/miketheman/pytest-socket


faydalı. Keflavich'i takiben, birim test setime nasıl entegre oldum. Bu, binlerce farklı ünite test vakasıyla (sokete ihtiyaç duyan < 100) ... ve doktrinlerin içinde ve dışında benim için çalışıyor.

here gönderdim. Kolaylık sağlamak için aşağıya dahil. Python 2.7.5 ile test edilmiştir, pytest == 2.7.0. (Klonlanmış 3 dosyalarla dizinde py.test --doctest-modules çalıştırmak kendiniz için test etmek için.)

_socket_toggle.py

from __future__ import print_function 
import socket 
import sys 

_module = sys.modules[__name__] 

def disable_socket(): 
    """ disable socket.socket to disable the Internet. useful in testing. 

    .. doctest:: 
     >>> enable_socket() 
     [!] socket.socket is enabled. 
     >>> disable_socket() 
     [!] socket.socket is disabled. Welcome to the desert of the real. 
     >>> socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     Traceback (most recent call last): 
     ... 
     RuntimeError: I told you not to use the Internet! 
     >>> enable_socket() 
     [!] socket.socket is enabled. 
     >>> enable_socket() 
     [!] socket.socket is enabled. 
     >>> disable_socket() 
     [!] socket.socket is disabled. Welcome to the desert of the real. 
     >>> socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     Traceback (most recent call last): 
     ... 
     RuntimeError: I told you not to use the Internet! 
     >>> enable_socket() 
     [!] socket.socket is enabled. 
    """ 
    setattr(_module, '_socket_disabled', True) 

    def guarded(*args, **kwargs): 
     if getattr(_module, '_socket_disabled', False): 
      raise RuntimeError("I told you not to use the Internet!") 
     else: 
      # SocketType is a valid public alias of socket.socket, 
      # we use it here to avoid namespace collisions 
      return socket.SocketType(*args, **kwargs) 

    socket.socket = guarded 

    print(u'[!] socket.socket is disabled. Welcome to the desert of the real.') 


def enable_socket(): 
    """ re-enable socket.socket to enable the Internet. useful in testing. 
    """ 
    setattr(_module, '_socket_disabled', False) 
    print(u'[!] socket.socket is enabled.') 

conftest.py

# Put this in the conftest.py at the top of your unit tests folder, 
# so it's available to all unit tests 
import pytest 
import _socket_toggle 


def pytest_runtest_setup(): 
    """ disable the interet. test-cases can explicitly re-enable """ 
    _socket_toggle.disable_socket() 


@pytest.fixture(scope='function') 
def enable_socket(request): 
    """ re-enable socket.socket for duration of this test function """ 
    _socket_toggle.enable_socket() 
    request.addfinalizer(_socket_toggle.disable_socket) 

test_example.py

# Example usage of the py.test fixture in tests 
import socket 
import pytest 

try: 
    from urllib2 import urlopen 
except ImportError: 
    import urllib3 
    urlopen = urllib.request.urlopen 


def test_socket_disabled_by_default(): 
    # default behavior: socket.socket is unusable 
    with pytest.raises(RuntimeError): 
     urlopen(u'https://www.python.org/') 


def test_explicitly_enable_socket(enable_socket): 
    # socket is enabled by pytest fixture from conftest. disabled in finalizer 
    assert socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
+0

Neden bir 'ConnectionError' istisnası yükseltmiyorsunuz? –

+0

@FemtoTrader Sanırım, bu _too_ doğru. Atanan hatayı, meşru bir 'ConnectionError' için atılacak bir hata ile karıştırmak istemiyoruz. Pratikte aslında bir Çalışma Zamanı Hatası alt sınıfı kullanıyorum ama bu örneği daha basit tutmak istedim – hangtwenty

+2

Python3 için çalışan bir güncelleme şansı var mı? Bunu bir pytest eklentisine dönüştürmeye yardımcı olmaktan memnuniyet duyarım. –

İlgili konular