Python: блокировать сетевые соединения в целях тестирования?
Я пытаюсь протестировать пакет, который предоставляет интерфейсы для нескольких веб-служб. Он имеет набор тестов, который должен тестировать большинство функций Без подключения к интернету. Однако есть некоторые затяжные тесты, которые могут попытаться подключиться к интернету / загрузить данные, и я хотел бы предотвратить их по двум причинам: Во-первых, чтобы убедиться, что мой набор тестов работает, если нет сетевого подключения; во-вторых, чтобы я не спамил веб-службы с избытком запросы.
Очевидное решение-отключить мою машину / выключить беспроводную связь, но когда я запускаю тесты на удаленной машине, это, очевидно, не работает.
Итак, мой вопрос: Могу ли я заблокировать доступ к сети / порту для одного процесса python? ("песочница" это, но просто блокирующие сетевые соединения)
(afaict, pysandbox этого не делает)
EDIT: я использую py.test, поэтому мне нужно решение, которое будет работать с py.test, в случае, если это повлияет на любые предлагаемые ответы.
2 ответов:
Обезьяна заплатки
socketдолжен сделать это:import socket def guard(*args, **kwargs): raise Exception("I told you not to use the Internet!") socket.socket = guardУбедитесь, что это выполняется перед любым другим импортом.
Update : теперь есть плагин pytest, который делает то же самое, что и этот ответ! Вы можете прочитать ответ, чтобы просто посмотреть, как все работает, но я настоятельно рекомендую использовать плагин вместо копирования-вставки моего ответа: -) смотрите здесь: https://github.com/miketheman/pytest-socket
Я нашел ответ Томаса Ороско очень полезным. Следуя за кефлавичем, вот как я интегрировался в свой набор модульных тестов. Это работает для меня с тысячами очень различные юнит-тесты (Я разместил здесь. В том числе и ниже для удобства. Тестировался с Python 2.7.5, pytest= = 2.7.0. (Чтобы проверить это самостоятельно, запустите
py.test --doctest-modulesв директории со всеми 3 клонированными файлами.)_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)
Comments