After you built the failing test_get_valid_html_response() test case in the previous lesson, you'll now head over to rescrape.py and build the function that you tried to call in your test.
Resolve The Errors
First, you'll want to make sure that the function even exists so that your test suite can import it correctly. You can start by writing a new empty function in rescrape.py named get_page_content():
def get_page_content():
pass
Run and Repeat
Once you've done that, head back to your terminal and run your tests another time. You'll receive a different output:
E
======================================================================
ERROR: test_get_valid_html_response (__main__.TestRescrape)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_rescrape.py", line 9, in test_get_valid_html_response
index_page = rescrape.get_page_content(BASE_URL)
TypeError: get_page_content() takes 0 positional arguments but 1 was given
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (errors=1)
As you can see from Python's response, it was now able to import the function from your rescrape.py file, but there was an issue with the function signature and how you tried to use it:
TypeError: get_page_content() takes 0 positional arguments but 1 was given
In your test case, you passed a variable, BASE_URL, to the get_page_content() function, but the empty definition of it didn't accept any arguments. So you'll have to update your production code once more:
def get_page_content(url):
pass
You added a parameter called url to your function definition in rescrape.py. Now you're ready to run your test suite another time. You'll see the following output:
E
======================================================================
ERROR: test_get_valid_html_response (__main__.TestRescrape)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_rescrape.py", line 10, in test_get_valid_html_response
self.assertEqual(index_page.status_code, 200)
AttributeError: 'NoneType' object has no attribute 'status_code'
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
Yippie! Yet another different error message. A changing error message is always a sign of progress. Your test code steps a bit further along, and it now tells you that the None object that your empty function returns doesn't have an attribute called .status_code. Fair enough! It's time to think in more detail about what your get_page_content() function should actually do.
Build The Function
What should your new function do? In the two lines of your test case, you actually worked out a complete blueprint for the function that you want to build.
Check the Blueprint
index_page = rescrape.get_page_content(BASE_URL): In this line, you defined that the function should be calledget_page_content()and that it'll take one argument, a URL. You also defined that it should have a return value.self.assertEqual(index_page.status_code, 200): In the second line, you defined that the return value of your function should be arequests.models.Response()object from therequestspackage, which have an attribute called.status_codethat holds the status code of the HTTP response it received.
Write the Function
With these instructions that you gave yourself when writing the test case, you can now complete the corresponding function in your production code:
def get_page_content(url):
"""Gets the response from a HTTP call to the URL."""
page = requests.get(url)
return page
In this code snippet, you use the .get() function of the requests library to take the URL that gets passed to get_page_content() and make an HTTP request.
You save the response of the request to a new variable, page, that will be of the requests.models.Response() type that has a .status_code attribute, and return that object from the function.
Test the Function
You can now give your test suite another go:
python3 -m unittest test_rescrape.py
And as a reward for all your hard work, unittest is finally satisfied and gives you a dot:
.
----------------------------------------------------------------------
Ran 1 test in 0.657s
OK
With this, you've finished your first test, as well as refactored your production code so that the test passed. Throughout doing this, you followed a test-driven-development approach, where you started by mapping out your tests and followed it up by writing the corresponding code.
You can now feel more secure that the get_page_content() function does what you want it to do, and you have a way to figure out if something with it stops working as expected. For example, when the recipe collection page gets taken down, the HTTP response won't have the 200 status code anymore, and your test_get_valid_html_response() will fail.
Summary: Transform Python Test Function
- With a failing test, the first step in TDD is to solve the errors
- After having a passed test, it is time to build the function
- If the function doesn't pass the test, then refactor the function until the test passes
How to Build Function in TDD
- Check the Blueprint
- Write the Function
- Test the Function