Test-Driven Development is great. If you're a Pythonista, it gets even better with pytest - a framework that makes building simple and scalable tests easy.
In this series, I'll be exploring the cool features that pytest offers to help make testing Python code a breeze.
Preparing your python environment
Let's set up our testing environment with virtualenv
. We'll be working with Python 3. cd
into your working directory and create a new virtual environment:
python3 -m venv env
Activate the virtual environment:
source env/bin/activate
Installing pytest
pip install pytest
That's all you need to do to get pytest ready. You can check the installed version by running:
pytest --version
Creating your first test
Say we need to create an app that says hello to the name you give it when it runs (I know, very original π
).
# simple hello world test
def hello_world(name):
pass
def test_hello():
assert hello_world("World!") == "Hello World!"
You'll notice that our test function name begins with the word test. That's how pytest discoveres test methods. Also, :
- Test files should be named
test_<something>.py
or<something>_test.py
- Test classes should be named
Test<Something>
Running pytest hello.py
should return:
collected 1 item
hello.py F [100%]
===================== FAILURES ======================
def test_hello():
> assert hello_world("World!") == "Hello World!"
E AssertionError: assert None == 'Hello World!'
E + where None = hello_world('World!')
hello.py:6: AssertionError
Pytest shows why the test failed: AssertionError: assert None == 'Hello World!β
. Obviously, we have no code in our hello function so letβs fix that.
def hello_world(name):
return "Hello {}".format(name)
def test_hello():
assert hello_world("World!") == "Hello World!"
Running pytest hello.py
should now return:
collected 1 item
hello.py . [100%]
==================== 1 passed in 0.04 seconds ======================
As you can see, itβs pretty easy to get started with testing in python with pytest. Now that we have everything set up, weβll be going into more advanced features as the series continues.
Top comments (8)
Hey Kinyanjui. Thanks for this series.
I'm just getting started with pytest. I have a program that has multiple user inputs. I wrote 3 basic tests so far. All using if statements then asserts.
When I run
pytest card.py -s
, the program runs and I have to input all the data, then I get the message whether the tests have passed or not.My question is, how can I run the tests without the code having to run? Does it depend on how I wrote the tests?
Hey @dmahely ! Thanks for reading, and I'm glad you liked it. Sorry for the late reply, it's been a while since I was here.
You can automate the tests by passing in mock data. Do you have the code hosted on GitHub or somewhere I can have a look so I can guide you on how to do it?
Is that what automated tests mean? π
The code was for a technical test that I've since submitted, and the instructions included not putting it on GitHub. May I reach out to you on Twitter?
Yeah, feel free to reach out on Twitter.
I receive an error which begins like this(I've called my python file "main.py" instead of "hello.py"):
ERRORS =================================================================
_______________________________________________________ ERROR collecting main.py ________________________________________________________
env\lib\site-packages_pytest\python.py:493: in _importtestmodule
...
Can you help me with that? By the way this is a great tutorial Kinyanjui, can't thank you enough.
(P.S: Also just since it might matter, I'm on Windows and I activated the env using ".\env\Scripts\activate.bat" instead of the one you did in your terminal. I tested pytest --version and it's installed successfully.)
P.S #2: Sorry, I fixed it. I had a typo. But the error was scary and unreadable! Thanks anyways I enjoyed it very much when the test passed! :) I didn't delete the error so if someone else bumps into the same error can see my comment.
P.S #3: How about writing the test functions in a separate file? How should we run them? Should we use globs in that case? e.g:
pytest test_*.py
?Hey @aderchox . If the test is in a different file, still just running
pytest
while in the project directory should discover the test files, as long as they're named in the formattest_*.py
.You can read more about test discovery here.
import re
import pytest
def check_email_format(email):
if not (re.match(r"([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$)", email)):
return False
return True
def test_email_exception():
assert check_email_format("good@email.com") == True
assert check_email_format("good.com") == False
Nice post.