-
Notifications
You must be signed in to change notification settings - Fork 100
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
197 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,197 @@ | ||
import os | ||
from unittest import mock | ||
import tempfile | ||
|
||
import pytest | ||
from requests import exceptions as req_exp | ||
from requests.models import Response | ||
from unittest.mock import patch | ||
from uk_bin_collection.get_bin_data import AbstractGetBinDataClass as agbdc | ||
from uk_bin_collection.get_bin_data import setup_logging | ||
import logging | ||
|
||
|
||
def mocked_requests_get(*args, **kwargs): | ||
class MockResponse: | ||
def __init__(self, json_data, status_code, raise_error_type): | ||
self.text = json_data | ||
self.status_code = status_code | ||
if raise_error_type is not None: | ||
self.raise_for_status = self.raise_error(raise_error_type) | ||
else: | ||
self.raise_for_status = lambda: None | ||
|
||
def raise_error(self, errorType): | ||
if errorType == "HTTPError": | ||
raise req_exp.HTTPError() | ||
elif errorType == "ConnectionError": | ||
raise req_exp.ConnectionError() | ||
elif errorType == "Timeout": | ||
raise req_exp.Timeout() | ||
elif errorType == "RequestException": | ||
raise req_exp.RequestException() | ||
return errorType | ||
|
||
if args[0] == "aurl": | ||
return MockResponse({"test_data": "test"}, 200, None) | ||
elif args[0] == "HTTPError": | ||
return MockResponse({}, 999, "HTTPError") | ||
elif args[0] == "ConnectionError": | ||
return MockResponse({}, 999, "ConnectionError") | ||
elif args[0] == "Timeout": | ||
return MockResponse({}, 999, "Timeout") | ||
elif args[0] == "RequestException": | ||
return MockResponse({}, 999, "RequestException") | ||
elif args[0] == "notPage": | ||
return MockResponse("not json", 200, None) | ||
return MockResponse(None, 404, "HTTPError") | ||
|
||
|
||
# Unit tests | ||
|
||
|
||
def test_logging_exception(): | ||
logging_dict = "SW1A 1AA" | ||
with pytest.raises(ValueError) as exc_info: | ||
result = setup_logging(logging_dict, "ROOT") | ||
assert exc_info.typename == "ValueError" | ||
|
||
|
||
def test_setup_logging_valid_config(): | ||
# Example of a minimal valid logging configuration dictionary | ||
logging_config = { | ||
"version": 1, | ||
"handlers": { | ||
"console": { | ||
"class": "logging.StreamHandler", | ||
"level": "DEBUG", | ||
}, | ||
}, | ||
"loggers": { | ||
"ROOT": { | ||
"handlers": ["console"], | ||
"level": "DEBUG", | ||
}, | ||
}, | ||
} | ||
logger_name = "ROOT" | ||
# Run the function with valid logging configuration | ||
logger = setup_logging(logging_config, logger_name) | ||
|
||
# Assert that logger is correctly configured | ||
assert logger.name == logger_name | ||
assert logger.level == logging.DEBUG | ||
|
||
|
||
@mock.patch("requests.get", side_effect=mocked_requests_get) | ||
def test_get_data(mock_get): | ||
page_data = agbdc.get_data("aurl") | ||
assert page_data.text == {"test_data": "test"} | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"url", ["HTTPError", "ConnectionError", "Timeout", "RequestException"] | ||
) | ||
@mock.patch("requests.get", side_effect=mocked_requests_get) | ||
def test_get_data_error(mock_get, url): | ||
with pytest.raises(Exception) as exc_info: | ||
result = agbdc.get_data(url) | ||
assert exc_info.typename == url | ||
|
||
|
||
def test_output_json(): | ||
bin_data = {"bin": ""} | ||
output = agbdc.output_json(bin_data) | ||
assert type(output) == str | ||
assert output == '{\n "bin": ""\n}' | ||
|
||
class ConcreteGetBinDataClass(agbdc): | ||
"""Concrete implementation of the abstract class to test abstract methods.""" | ||
def parse_data(self, page: str, **kwargs) -> dict: | ||
return {"mock_key": "mock_value"} | ||
|
||
def update_dev_mode_data(self, council_module_str, this_url, **kwargs): | ||
# You can implement the method or delegate it to the abstract class's method | ||
super().update_dev_mode_data(council_module_str, this_url, **kwargs) | ||
|
||
@pytest.fixture | ||
def concrete_class_instance(): | ||
return ConcreteGetBinDataClass() | ||
|
||
def test_get_and_parse_data_no_skip_get_url(concrete_class_instance): | ||
mock_page = "mocked page content" | ||
mock_parsed_data = {"mock_key": "mock_value"} | ||
|
||
with mock.patch.object(concrete_class_instance, 'get_data', return_value=mock_page) as mock_get_data, \ | ||
mock.patch.object(concrete_class_instance, 'parse_data', return_value=mock_parsed_data) as mock_parse_data: | ||
|
||
result = concrete_class_instance.get_and_parse_data("http://example.com") | ||
|
||
mock_get_data.assert_called_once_with("http://example.com") | ||
mock_parse_data.assert_called_once_with(mock_page, url="http://example.com") | ||
assert result == mock_parsed_data | ||
|
||
def test_get_and_parse_data_skip_get_url(concrete_class_instance): | ||
mock_parsed_data = {"mock_key": "mock_value"} | ||
|
||
with mock.patch.object(concrete_class_instance, 'parse_data', return_value=mock_parsed_data) as mock_parse_data: | ||
|
||
result = concrete_class_instance.get_and_parse_data("http://example.com", skip_get_url=True) | ||
|
||
mock_parse_data.assert_called_once_with("", url="http://example.com", skip_get_url=True) | ||
assert result == mock_parsed_data | ||
|
||
@pytest.fixture | ||
def setup_test_update_dev_mode_data(): | ||
"""Fixture to set up and tear down the environment for test_update_dev_mode_data""" | ||
# Create a temporary directory to simulate the working directory | ||
test_dir = tempfile.TemporaryDirectory() | ||
|
||
# Patch os.getcwd() to return the temporary directory | ||
cwd_patch = patch('os.getcwd', return_value=test_dir.name) | ||
mock_getcwd = cwd_patch.start() | ||
|
||
# Ensure the nested directory structure exists | ||
os.makedirs(os.path.join(test_dir.name, "uk_bin_collection", "tests")) | ||
|
||
# Yield control back to the test, then clean up after the test | ||
yield test_dir.name # Provide the test with the temporary directory | ||
|
||
# Teardown | ||
test_dir.cleanup() | ||
cwd_patch.stop() | ||
|
||
|
||
def test_update_dev_mode_data(setup_test_update_dev_mode_data): | ||
"""Test update_dev_mode_data method to ensure input.json is updated correctly""" | ||
# The setup fixture returns the mocked current working directory | ||
mock_cwd = setup_test_update_dev_mode_data | ||
|
||
# Create an instance of the concrete class that inherits from AbstractGetBinDataClass | ||
obj = ConcreteGetBinDataClass() | ||
|
||
# Define input arguments for the method | ||
council_module_str = 'test_council_module' | ||
this_url = 'https://example.com' | ||
kwargs = { | ||
'postcode': '12345', | ||
'paon': '1A', | ||
'uprn': '100012345', | ||
'usrn': '200012345', | ||
'web_driver': 'mocked_web_driver', | ||
'skip_get_url': True, | ||
} | ||
|
||
# Call the method being tested on the instance | ||
obj.update_dev_mode_data(council_module_str, this_url, **kwargs) | ||
|
||
# Verify that input.json was created in the correct location | ||
input_file_path = os.path.join(mock_cwd, "uk_bin_collection", "tests", "input.json") | ||
assert os.path.exists(input_file_path) | ||
|
||
# Read the contents of the file and make necessary assertions | ||
with open(input_file_path, 'r') as f: | ||
file_content = f.read() | ||
|
||
# Example assertion - check if certain values exist in the file content (based on your actual file format) | ||
assert '100012345' in file_content # Checking UPRN as an example |