You own an ecommerce store that sells costumes for dogs 🐶. You'd like to analyze your web traffic by measuring the count of unique visitors amongst your web sessions data. Additionally, you want the ability to filter by date, so you can answer questions like
How many visitors visited my site?
and
How many visitors visited my site on February 20th, 2022?
You come up with the following count_visitors() function that you place inside measures.py.
To test it, you create test_measures.py as follows.
You have a problem.. Both of your test functions call the load_sessions() function in order to load the sessions data, but this data is really expensive (slow) to fetch. (In theory, load_sessions() might connect to a database and run an expensive query.) See if you can cut your tests runtime in half 😉.
Run with messages
Notice the print() statement inside the load_sessions() function. To view the output of this print statement in the console, run the tests with pytest -s as opposed to simply pytest. The -s flag tells pytest not to capture the result of standard out as it normally does.
Now when we run pytest -s, we get the following output:
Notice the message "loading sessions data.. hold on a sec" appears once - not twice as it did originally. This indicates that the expensive load_sessions() function only ran once.
The trick to this solution is to make use of pytest's fixture decorator which allows us to cache the output value of a function. In this case, we cache the output of load_sessions() so we can use it in test_count_visitors() and then reuse it in test_count_visitors_on_date(). To make this work, note a few things:
We have to import pytest
We have to decorate load_sessions() with @pytest.fixture(scope="module").
scope="module" tells pytest it can reuse the data within the same module (python file). However, if we were to reference the load_sessions() function from a different module, the function would be re-executed.
We have to pass load_sessions into its dependent test functions as a parameter, and tweak the internals accordingly.