jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/329644 )
Change subject: Using pytest-httpbin ......................................................................
Using pytest-httpbin
Now http_tests use pytest-httpbin if pytest is used to run the tests Otherwise, http://httpbin.org is used
Bug: T153560 Change-Id: I2000fed5e5273dbfef5d51ac81698a32c7fc5676 --- M dev-requirements.txt M tests/aspects.py A tests/conftest.py M tests/http_tests.py 4 files changed, 97 insertions(+), 34 deletions(-)
Approvals: John Vandenberg: Looks good to me, approved jenkins-bot: Verified
diff --git a/dev-requirements.txt b/dev-requirements.txt index edd5005..44a3038 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -7,6 +7,7 @@ pytest-runner pytest-cov pytest-attrib +pytest-httpbin
six
diff --git a/tests/aspects.py b/tests/aspects.py index 3ac9ca6..305c4be 100644 --- a/tests/aspects.py +++ b/tests/aspects.py @@ -29,6 +29,7 @@ UITestCase: Not integrated; direct subclass of unittest.TestCase. """ +import imp import inspect import itertools import os @@ -483,6 +484,20 @@ if not hasattr(cls, 'sites'): return
+ # Check is pytest is used and pytest_httpbin module is installed. + if hasattr(sys, '_test_runner_pytest'): + try: + imp.find_module('pytest_httpbin') + httpbin_used = True + except ImportError: + httpbin_used = False + else: + httpbin_used = False + + # If pytest_httpbin will be used during tests, then remove httpbin.org from sites. + if httpbin_used: + cls.sites = {k: v for k, v in cls.sites.items() if 'httpbin.org' not in v['hostname']} + for key, data in cls.sites.items(): if 'hostname' not in data: raise Exception('%s: hostname not defined for %s' diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..24965e0 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +"""Used by pytest to do some preparation work before running tests.""" +# +# (C) Pywikibot team, 2017 +# +# Distributed under the terms of the MIT license. +# +from __future__ import absolute_import, unicode_literals + +import sys + + +def pytest_configure(config): + """Set the sys._test_runner_pytest flag to True, if pytest is used to run tests.""" + sys._test_runner_pytest = True diff --git a/tests/http_tests.py b/tests/http_tests.py index e62b390..72db94c 100644 --- a/tests/http_tests.py +++ b/tests/http_tests.py @@ -27,6 +27,56 @@ from tests import join_images_path from tests.aspects import unittest, TestCase, DeprecationTestCase, require_modules
+try: + import pytest_httpbin + optional_pytest_httpbin_cls_decorator = pytest_httpbin.use_class_based_httpbin +except ImportError: + pytest_httpbin = None + + def optional_pytest_httpbin_cls_decorator(f): + """Empty decorator in case pytest_httpbin is not installed.""" + return f + + +@optional_pytest_httpbin_cls_decorator +class HttpbinTestCase(TestCase): + + """ + Custom test case class, which allows doing dry httpbin tests using pytest-httpbin. + + Test cases, which use httpbin, need to inherit this class. + """ + + sites = { + 'httpbin': { + 'hostname': 'httpbin.org', + }, + } + + def get_httpbin_url(self, path=''): + """ + Return url of httpbin. + + If pytest is used, returns url of local httpbin server. + Otherwise, returns: http://httpbin.org + """ + if hasattr(self, 'httpbin'): + return self.httpbin.url + path + else: + return 'http://httpbin.org' + path + + def get_httpbin_hostname(self): + """ + Return httpbin hostname. + + If pytest is used, returns hostname of local httpbin server. + Otherwise, returns: httpbin.org + """ + if hasattr(self, 'httpbin'): + return '{0}:{1}'.format(self.httpbin.host, self.httpbin.port) + else: + return 'httpbin.org' +
class HttpTestCase(TestCase):
@@ -157,7 +207,7 @@ 'InsecureRequestWarning')
-class TestHttpStatus(TestCase): +class TestHttpStatus(HttpbinTestCase):
"""Test HTTP status code handling and errors."""
@@ -177,7 +227,7 @@ """Test that a HTTP 504 raises the correct exception.""" self.assertRaises(pywikibot.Server504Error, http.fetch, - uri='http://httpbin.org/status/504') + uri=self.get_httpbin_url('/status/504'))
def test_server_not_found(self): """Test server not found exception.""" @@ -316,15 +366,9 @@ self._test_fake_user_agent_randomness()
-class LiveFakeUserAgentTestCase(TestCase): +class LiveFakeUserAgentTestCase(HttpbinTestCase):
"""Test the usage of fake user agent.""" - - sites = { - 'httpbin': { - 'hostname': 'httpbin.org', - }, - }
def setUp(self): """Set up the unit test.""" @@ -340,22 +384,22 @@ """Test `use_fake_user_agent` argument of http.fetch.""" # Existing headers r = http.fetch( - 'http://httpbin.org/status/200', headers={'user-agent': 'EXISTING'}) + self.get_httpbin_url('/status/200'), headers={'user-agent': 'EXISTING'}) self.assertEqual(r.headers['user-agent'], 'EXISTING')
# Argument value changes - r = http.fetch('http://httpbin.org/status/200', use_fake_user_agent=True) + r = http.fetch(self.get_httpbin_url('/status/200'), use_fake_user_agent=True) self.assertNotEqual(r.headers['user-agent'], http.user_agent()) - r = http.fetch('http://httpbin.org/status/200', use_fake_user_agent=False) + r = http.fetch(self.get_httpbin_url('/status/200'), use_fake_user_agent=False) self.assertEqual(r.headers['user-agent'], http.user_agent()) r = http.fetch( - 'http://httpbin.org/status/200', use_fake_user_agent='ARBITRARY') + self.get_httpbin_url('/status/200'), use_fake_user_agent='ARBITRARY') self.assertEqual(r.headers['user-agent'], 'ARBITRARY')
# Manually overridden domains - config.fake_user_agent_exceptions = {'httpbin.org': 'OVERRIDDEN'} + config.fake_user_agent_exceptions = {self.get_httpbin_hostname(): 'OVERRIDDEN'} r = http.fetch( - 'http://httpbin.org/status/200', use_fake_user_agent=False) + self.get_httpbin_url('/status/200'), use_fake_user_agent=False) self.assertEqual(r.headers['user-agent'], 'OVERRIDDEN')
@require_modules('browseragents') @@ -561,7 +605,7 @@ self.assertIs(main_module_cookie_jar, http.cookie_jar)
-class QueryStringParamsTestCase(TestCase): +class QueryStringParamsTestCase(HttpbinTestCase):
""" Test the query string parameter of request methods. @@ -570,15 +614,9 @@ urldecoded query string parameters. """
- sites = { - 'httpbin': { - 'hostname': 'httpbin.org', - }, - } - def test_no_params(self): """Test fetch method with no parameters.""" - r = http.fetch(uri='https://httpbin.org/get', params={}) + r = http.fetch(uri=self.get_httpbin_url('/get'), params={}) self.assertEqual(r.status, 200)
content = json.loads(r.content) @@ -591,7 +629,7 @@ HTTPBin returns the args in their urldecoded form, so what we put in should be the same as what we get out. """ - r = http.fetch(uri='https://httpbin.org/get', params={'fish&chips': 'delicious'}) + r = http.fetch(uri=self.get_httpbin_url('/get'), params={'fish&chips': 'delicious'}) self.assertEqual(r.status, 200)
content = json.loads(r.content) @@ -604,7 +642,7 @@ HTTPBin returns the args in their urldecoded form, so what we put in should be the same as what we get out. """ - r = http.fetch(uri='https://httpbin.org/get', + r = http.fetch(uri=self.get_httpbin_url('/get'), params={'fish%26chips': 'delicious'}) self.assertEqual(r.status, 200)
@@ -612,20 +650,14 @@ self.assertDictEqual(content['args'], {'fish%26chips': 'delicious'})
-class DataBodyParameterTestCase(TestCase): +class DataBodyParameterTestCase(HttpbinTestCase): """Test that the data and body parameters of fetch/request methods are equivalent.""" - - sites = { - 'httpbin': { - 'hostname': 'httpbin.org', - }, - }
def test_fetch(self): """Test that using the data parameter and body parameter produce same results.""" - r_data = http.fetch(uri='https://httpbin.org/post', method='POST', + r_data = http.fetch(uri=self.get_httpbin_url('/post'), method='POST', data={'fish&chips': 'delicious'}) - r_body = http.fetch(uri='https://httpbin.org/post', method='POST', + r_body = http.fetch(uri=self.get_httpbin_url('/post'), method='POST', body={'fish&chips': 'delicious'})
self.assertDictEqual(json.loads(r_data.content),
pywikibot-commits@lists.wikimedia.org