Reputation: 51
I have a function that makes a query to an API (a pseudo-API hosted locally) to retrieve a list of values. Nothing fancy.
When trying to test a function containing this API call, I obviously want to mock it. But it is still making calls to the actual API instead of returning mock values that I created in the test itself.
def display_unhealthy_services():
healthy_entries = {}
unhealthy_services = []
all_ip_addresses = retrieve_all_ip_addresses()
for ip in all_ip_addresses:
ip_info = get_ip_status_info(ip)
if ip_info[2] == "Healthy":
if ip_info[1] not in healthy_entries:
healthy_entries[ip_info[1]] = 1
else:
healthy_entries[ip_info[1]] += 1
for key, values in healthy_entries.items():
if values < 2:
unhealthy_services.append(key)
output_string = "\n".join(unhealthy_services)
if output_string != "":
click.echo("Services with less than 2 healthy instances include: ")
click.echo(output_string)
else:
print("Cat", all_ip_addresses)
click.secho("Your DevOps engineers are too good! There are no unhealthy services!",fg="black", bg="yellow")
Here is my pytest:
@mock.patch("get_average.retrieve_all_ip_addresses", return_value=["8.8.8.8", "8.8.8.9"])
@mock.patch("get_ip_info.get_ip_status_info")
def test_display_unhealthy_services_if_they_exist(mock_ip_status, mock_ip_addresses):
# Set up the mock return values for the functions
mock_ip_status.side_effect = [
("8.8.8.8", "service1", "Healthy", 40, 50),
("8.8.8.9", "service2", "Unhealthy", 90, 30)
]
# Invoke the display_unhealthy_services() function using CliRunner
runner = CliRunner()
result = runner.invoke(display_unhealthy_services)
# Assert that the output is as expected
expected_output = "Services with less than 2 healthy instances include: \nservice2"
assert expected_output in result.output
# check if the function calls are being made correctly
mock_ip_status.assert_called()
mock_ip_addresses.assert_called()
As you can see, I am trying to retrieve all IP addresses, but in my test I am expecting to only get ["8.8.8.8", "8.8.8.9"].
But when I run the test, it still querys the actual API and I cannot see ["8.8.8.8", "8.8.8.9"] at all.
I've tried rewriting it in pytest several times but to no avail. It keeps on returning values that the function would get from querying the actual API.
TLDR: I have function A and function B.
Function A is in function B. When function A gets called when function B gets called.
Now how do I test function B, whilst mocking values of function A?
I want to control the output of function A, so that when function B gets called, it will use the input values that I decide
Upvotes: 4
Views: 1336
Reputation: 2558
I don't test your code on my system, but I think that you are patching the functions in the wrong modules.
You have to mock the objects imported by the module that contains the display_unhealthy_services
function and not the objects in the file where they are defined.
I suppose that the production function display_unhealthy_services
is defined in the module display_services.py
and in this module are present the following import:
from get_average import retrieve_all_ip_addresses
from get_ip_info import get_ip_status_info
With this hypothesis, in the test code, the patch()
should become:
# NOTE the presence of display_services instead of get_average
@mock.patch("display_services.retrieve_all_ip_addresses", return_value=["8.8.8.8", "8.8.8.9"])
# NOTE the presence of display_services instead of get_ip_info
@mock.patch("display_services.get_ip_status_info")
I didn't check the other part of your test function, but I think that this changes could help you to set the return value for your mock objects.
Upvotes: 6