├── .gitignore ├── README.md ├── api.github.com ├── repos │ └── appneta │ │ └── burndown └── users │ └── danriti ├── github.py ├── mocks ├── __init__.py └── github.py ├── requirements.txt └── test_github.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | env 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python-mocked-service 2 | 3 | Example of mocking an external service in Python tests. 4 | 5 | ### Changes 6 | 7 | | # | Commit | 8 | | --- | ------ | 9 | | 1 | [Add `get_repository` function][10] | 10 | | 2 | [Add `test_get_repository` test case][11] | 11 | | 3 | [Create a `repository` mock][12] | 12 | | 4 | [Update test case to use `repository` mock][13] | 13 | | 5 | [Create a repository test fixture for `burndown`][1] | 14 | | 6 | [Refactor `repository` mock to use test fixtures][22] | 15 | | 7 | [Rename `repository` mock to `resource_get`][25] | 16 | | 8 | [Add `get_user` function][26] | 17 | | 9 | [Add `test_get_user` test case][27] | 18 | | 10 | [Create a user test fixture for `danriti`][28] | 19 | | 11 | [Create `Resource` class for encapsulating file handling][31] | 20 | | 12 | [Add error handling if resource is not available][32] | 21 | 22 | 23 | [1]: https://github.com/danriti/python-mocked-service/commit/aff2c1832def24d8e771abbec756ea7c7822bb57 24 | [10]: https://github.com/danriti/python-mocked-service/commit/c97eb466131c66cd3daf0b4c5e0014a5a4756bb0 25 | [11]: https://github.com/danriti/python-mocked-service/commit/5003a893b1c52b662d4618a754e921e857e65f9f 26 | [12]: https://github.com/danriti/python-mocked-service/commit/5c69623d77bbe5780d5d68dbc5e85bba08ae3770 27 | [13]: https://github.com/danriti/python-mocked-service/commit/332f03211dbe307b8dcce9b11f7e939f54262276 28 | [22]: https://github.com/danriti/python-mocked-service/commit/b8304d3a6e7225b2e2d2d9bdf3a7c623f095fba0 29 | [25]: https://github.com/danriti/python-mocked-service/commit/f4e91a12fc401dd7f39f96a315e4eab19e8b115f 30 | [26]: https://github.com/danriti/python-mocked-service/commit/9c7cad198d0e2eed8053198c08fe12f093ad17f5 31 | [27]: https://github.com/danriti/python-mocked-service/commit/95e2c572fba2b7eec5bf6492876906b22c98e441 32 | [28]: https://github.com/danriti/python-mocked-service/commit/c4f45acd4e29beff06b410892324c041f494641d 33 | [31]: https://github.com/danriti/python-mocked-service/commit/7fc95b4a8a53b5555ccef529271aaca76fd3cf8e 34 | [32]: https://github.com/danriti/python-mocked-service/commit/40a4ef112e11cba668b4d62f528e98b50d0041cd 35 | -------------------------------------------------------------------------------- /api.github.com/repos/appneta/burndown: -------------------------------------------------------------------------------- 1 | {"name":"burndown"} 2 | -------------------------------------------------------------------------------- /api.github.com/users/danriti: -------------------------------------------------------------------------------- 1 | {"login": "danriti"} 2 | -------------------------------------------------------------------------------- /github.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | github 5 | 6 | This module contains methods for accessing the Github API v3. 7 | 8 | https://developer.github.com/v3/ 9 | 10 | """ 11 | 12 | import requests 13 | 14 | 15 | GITHUB_AUTHORITY = 'api.github.com' 16 | 17 | 18 | def get_repository(owner, repo): 19 | """ Get respository information. 20 | 21 | :param owner: The name of the repository owner. 22 | :param repo: The name of the repository. 23 | :rtype: dict 24 | 25 | """ 26 | uri = 'https://{0}/repos/{1}/{2}'.format(GITHUB_AUTHORITY, owner, repo) 27 | response = requests.get(uri) 28 | response.raise_for_status() 29 | return response.json() 30 | 31 | 32 | def get_user(user): 33 | """ Get user information. 34 | 35 | :param user: The name of the GitHub user. 36 | :rtype: dict 37 | 38 | """ 39 | uri = 'https://{0}/users/{1}'.format(GITHUB_AUTHORITY, user) 40 | response = requests.get(uri) 41 | response.raise_for_status() 42 | return response.json() 43 | -------------------------------------------------------------------------------- /mocks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danriti/python-mocked-service/2b1cb467aca212d5ab123e4e370ed6da086d4fa4/mocks/__init__.py -------------------------------------------------------------------------------- /mocks/github.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Mocks for the Github API library tests. 5 | 6 | """ 7 | 8 | 9 | from httmock import response, urlmatch 10 | 11 | 12 | NETLOC = r'(.*\.)?api\.github\.com$' 13 | HEADERS = {'content-type': 'application/json'} 14 | GET = 'get' 15 | 16 | 17 | class Resource: 18 | """ A GitHub resource. 19 | 20 | :param path: The file path to the resource. 21 | 22 | """ 23 | 24 | def __init__(self, path): 25 | self.path = path 26 | 27 | def get(self): 28 | """ Perform a GET request on the resource. 29 | 30 | :rtype: str 31 | 32 | """ 33 | with open(self.path, 'r') as f: 34 | content = f.read() 35 | return content 36 | 37 | 38 | @urlmatch(netloc=NETLOC, method=GET) 39 | def resource_get(url, request): 40 | file_path = url.netloc + url.path 41 | try: 42 | content = Resource(file_path).get() 43 | except EnvironmentError: 44 | # catch any environment errors (i.e. file does not exist) and return a 45 | # 404. 46 | return response(404, {}, HEADERS, None, 5, request) 47 | return response(200, content, HEADERS, None, 5, request) 48 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | argparse==1.2.1 2 | httmock==1.2.2 3 | requests==2.3.0 4 | wsgiref==0.1.2 5 | -------------------------------------------------------------------------------- /test_github.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | Tests for the Github API library. 5 | 6 | """ 7 | 8 | import unittest 9 | 10 | from httmock import with_httmock 11 | 12 | import github 13 | import mocks.github 14 | 15 | 16 | class TestGithub(unittest.TestCase): 17 | 18 | @with_httmock(mocks.github.resource_get) 19 | def test_get_repository(self): 20 | owner = 'appneta' 21 | repo = 'burndown' 22 | 23 | results = github.get_repository(owner, repo) 24 | 25 | self.assertNotEqual(results, None) 26 | self.assertIsInstance(results, dict) 27 | self.assertTrue('name' in results) 28 | self.assertEqual(results['name'], repo) 29 | 30 | @with_httmock(mocks.github.resource_get) 31 | def test_get_user(self): 32 | user = 'danriti' 33 | 34 | results = github.get_user(user) 35 | 36 | self.assertNotEqual(results, None) 37 | self.assertIsInstance(results, dict) 38 | self.assertTrue('login' in results) 39 | self.assertEqual(results['login'], user) 40 | 41 | if __name__ == '__main__': 42 | unittest.main() 43 | --------------------------------------------------------------------------------