how to make a python test driven development environment
preview
This is one way to make a Python Test Driven Development project. I walk through making the folders (directories) and files for the environment, including setting up the first test
By the end of the chapter you will be know these commands better
mkdir
cd
touch
echo
cat
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install --requirement requirements.txt
pytest-watch
deactivate
history
questions about making a Python Test Driven Development Environment
Here are questions you can answer after going through this chapter
requirements
get an Integrated Development Environment (IDE). Here are a few options
-
If you are on MacOS and using Visual Studio Code, Configure the path so you can open Visual Studio Code from the command line later
-
Windows requirements
If you are using a Windows computer, install Windows Subsystem for Linux
If you cannot install Windows Subsystem for Linux, you can make a Python Test Driven Development Environment on Windows without Windows Subsystem for Linux instead of this chapter
Linux/Windows Subsystem for Linux requirements
Attention
Do this only if you are using Linux or Windows Subsystem for Linux. MacOS users should not do this section
Open a terminal then type this to update the Linux package manager
sudo apt updateTip
you can do a full upgrade if you want
sudo apt full-upgrade --yestype this in the terminal to install Python
sudo apt install python3 python3-venv --yes
how to make a Python Test Driven Development environment manually
I choose magic as the name for this project
I open
Terminalin the menu bar at the top of the Integrated Development Environment (IDE), then clickNew Terminalto open a terminalI change directory to where I will put all the projects from this book. I type cd in the terminal
Note
You can skip this step if you are already in the
pumping_pythondirectorycd pumping_pythonthe terminal shows
cd: no such file or directory: pumping_pythonthe folder (directory) does NOT exist. I need to make it
I use the mkdir program to make the
pumping_pythonfolder (directory)mkdir pumping_pythonthe terminal goes back to the command line
I try changing directory again
cd pumping_pythonthe terminal shows I am now in the
pumping_pythonfolder (directory).../pumping_pythonI type tree in the terminal to see what files and folders are in the
pumping_pythondirectorytreewhen tree is not installed on the computer, the terminal shows
tree: command not foundI need to install tree to use it
Attention
if you are using MacOS type this in the terminal
first install brew (The Missing Package Manager for MacOS), if you do not have it already
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"brew install treeor
Attention
if you are using Linux or Windows Subsystem for Linux type this in the terminal
sudo apt install tree --yesafter the computer installs tree, I run the command again
treewhen tree is installed on the computer, the terminal shows
. 0 directories, 0 filesNote
If you have done other work in the
pumping_pythonfolder there will be files and folders not 0 directories and 0 files
how to make a directory for the project
I change directory to the
magicproject in thepumping_pythonfoldercd magicthe terminal shows
cd: no such file or directory: magicthe
magicfolder does NOT exist yetI make the
magicdirectorymkdir magicthis makes a folder (directory) for the project where its files will stay
I use tree again
treethe terminal shows
. └── magic
how to change directory to the project
I try cd again
cd magic
the terminal shows I am now in the magic folder I just made in the pumping_python folder
.../pumping_python/magic
how to run a Python program
I use Python to run the magic program
python3 src/magic.py
the terminal shows
python3: can't open file '.../pumping_python/magic/src/magic.py': [Errno 2] No such file or directory
the computer cannot find the program because it does not exist, yet
how to make a directory for the source code
I make a child folder in the
magicdirectory for the programmkdir srcthe terminal goes back to the command line
I use tree to see what changed in the
magicdirectorytreethe terminal shows
. └── srcI try to run the
magicprogram againpython3 src/magic.pythe terminal shows the same error from before. I have to make the file
how to make an empty file
I use touch to make an empty file in the
srcfoldertouch src/magic.pythe terminal goes back to the command line
I use tree to see what folders and files I now have
treethe terminal shows
. └── src └── magic.pytouch is a program that makes an empty file with the name. I can give it the directory I want to put the file in as part of the name, in this case
touch src/magic.pymakes a file namedmagic.pyin thesrcfolderI try to run the
magicprogram againpython3 src/magic.pythe terminal goes back to the command line. Success! Even though
magic.pydoes not do anything because there is no code in it, I can successfully run it because it exists.
test_failure
how to manually run tests
I use the unittest module from the Python standard library that comes with Python to run tests. I type this in the terminal
python3 -m unittestthe terminal shows
---------------------------------------------------------------------- Ran 0 tests in 0.000s NO TESTS RANpython3is the Python program-mis an option/switch passed when calling Python to run the module, unittest in this casea Python module is any file that ends with
.py, this means somewhere on the computer there is a file namedunittest.py, see the source code for unittest here
I do not have any tests yet, so there is nothing to run
how to make a directory for the tests
how to make a Python file to hold the tests in the ‘tests’ folder
I use touch to add an empty file to the
testsdirectory for the actual testtouch tests/magic.pythe terminal goes back to the command line
I use tree to see what the project looks like so far
treethe terminal shows
. ├── src │ └── magic.py └── tests └── magic.pyI run the test again
python3 -m unittestthe terminal shows
NO TESTS RAN
RED: make it fail
I open
tests/magic.pywith the Integrated Development Environment (IDE) to open it in the editorI add the Python code below in
tests/magic.pyin the editorNote
the line numbers below are a guide, you do not need to copy them
1import unittest 2 3 4class TestMagic(unittest.TestCase): 5 6 def test_failure(self): 7 self.assertFalse(True)Here is an explanation of the code I typed in the file
import unittestimports the unittest module from the Python standard library, this is what I am using for testingclass TestMagicclassis the Python keyword for making classes - a group of attributes (values) and methods (functions) that belong together, I cover this in more detail in the classes chapterTestMagicis the name I gave this class and will hold the testImportant
I can use any name for the test class, it MUST start with
Testor unittest will NOT run the tests in itunittest.TestCase is a class from the unittest module that has methods for testing
class TestMagic(unittest.TestCase)definesTestMagicas a “child” of unittest.TestCase which means I can use its methods and attributes
def test_failuredef is the Python keyword for making methods (functions), see functions for more
test_failureis the name of the method I used for this first testImportant
I can use any name for the test method, it MUST start with
test_or unittest will NOT run the tests in itself.lets me use attributes and methods of theTestMagicclass which is a “child” of the unittest.TestCase class, instead of usingTestMagic().orunittest.TestCase().Important
the name
selfis Python convention. I can use any name but it is easier to stick with convention for this conceptself.assertFalse(True)is an assertionassertFalse is a method in the unittest.TestCase class that checks if its input is False
True is given as the input
I expect this line to fail because True is not False. If it does not fail, then Python and I have a problem
I turn on the
Auto Savefeature in the Integrated Development Environment (IDE) to automatically save files when I make a change so that I do not repeat myself by saving (ctrl+s (Windows/Linux) or command+s (mac)) every time I make a changeAttention
Turn on the
Auto Savefeature in your Integrated Development Environment (IDE)I try the command again to run the tests in the terminal
python3 -m unittestthe terminal shows
NO TESTS RANI need to tell Python that the
testsfolder is a Python package, so it can find the tests
how to make the tests a Python package
I use touch to add an empty file with the name
__init__.pyin thetestsfolderAttention
use 2 underscores (__) before and after
initfor__init__.pynot_init_.pytouch tests/__init__.pythe terminal goes back to the command line
I run the tree command to see what changed
treethe terminal shows
. ├── src │ └── magic.py └── tests ├── __init__.py └── magic.pyI try to run the tests again
python3 -m unittestthe terminal shows
NO TESTS RANI need to tell Python that
magic.pyin thetestsfolder is a test fileI close
magic.pyin the editor of the Integrated Development Environment (IDE)Caution
if you do not close
magic.pyyou will end up with 3 files in thetestsfolder after the next step (instead of 2), because theAuto Savefeature (enabled earlier) will save the original file after you change its name
how to change the name of a file
I use the mv program to change the name of
magic.pyin thetestsfolder totest_magic.pymv tests/magic.py tests/test_magic.pythe terminal goes back to the command line
I use tree with the
-Loption to see what I have so fartree -L 2the terminal shows
Note
if you do not see
__pycache__in the list do not worry, the important thing is that you renamedmagic.pytotest_magic.pyfor unittest to find the test. ├── src │ └── magic.py └── tests ├── __init__.py ├── __pycache__ └── test_magic.pythe
-Loption tells tree how deep to go when showing the folders and files, I use2to make it show only the first level of contents of the child foldersI run the tests again
python3 -m unittestthe terminal shows AssertionError
F ============================================================= FAIL: test_failure (tests.test_magic.TestMagic.test_failure) ------------------------------------------------------------- Traceback (most recent call last): File "...pumping_python/magic/tests/test_magic.py", line 7, in test_failure self.assertFalse(True) ~~~~~~~~~~~~~~~~^^^^^^ AssertionError: True is not false ------------------------------------------------------------- Ran 1 test in A.XYZs FAILED (failures=1)Important
I can use any name for the test file but it must start with
test_or unittest will NOT run the tests in the fileThis is the
REDpart of the Test Driven Development cycle. The message in the terminal is about the failure, I like to read these from the bottom up, here is an explanation of each line, starting from the last line on the screenFAILED (failures=1)the number of failuresRan 1 test in A.XYZsthe number of tests it ran and how long they tookAssertionError: True is not falsethe Error (Exception) that happened and its message, in this case AssertionError because True is not Falseself.assertFalse(True)the line of code that caused AssertionError~~~~~~~~~~~~~~~~^^^^^^points to the part of the line above that Python thinks caused the errorFile ".../magic/tests/test_magic.py", line 7, in test_failurethe line number of the code that caused the error and the location of the file where it isTraceback (most recent call last):all the information shown after this line that is indented to the right shows the calls that led to the failure, this is why I like to read it from the bottom upFAIL: test_failure (tests.test_magic.TestMagic.test_failure)is a header with information in dot notation about the failing test methodtests.test_magic.TestMagic.test_failureis the location of the failing testtestsis thetestsfolderTestMagicis the class defined on line 4 intest_magic.pytest_failureis the method (function) defined on line 6 intest_magic.py
Fshows a failure
I hold ctrl (Windows/Linux) or option or command (MacOS) on the keyboard and use the mouse to click on
File ".../pumping_python/magic/tests/test_magic.py", line 7in the terminal, and the Integrated Development Environment (IDE) opens the file in the editor with the cursor at the line where the failure happened
GREEN: make it pass
I change True to False on line 7 of test_magic.py in the editor
7 self.assertFalse(False)
I run the test again in the terminal
python3 -m unittest
the test passes! The terminal shows
.
------------------------------------------------------
Ran 1 test in A.XYZs
OK
cue CELEBRATION MUSIC AND DANCE! I am GREEN!!
REFACTOR: make it better
Keep a list of Errors/Exceptions that show up in the terminal as you go through this book to know them better, it helps when you run into them later. I add a list with AssertionError in test_magic.py in the editor
1import unittest
2
3
4class TestMagic(unittest.TestCase):
5
6 def test_failure(self):
7 self.assertFalse(True)
8
9
10# Exceptions seen
11# AssertionError
I ran python3 -m unittest a few times to see the test fail, I ran python3 -m unittest again to see the test pass. I will have to run python3 -m unittest again when I add any code, to make sure tests that were passing do not start failing and that the new code I add does what I want.
This means I have to run python3 -m unittest for each part of the Test Driven Development cycle or any time there is a code change.
I do not want to type python3 -m unittest again, it is better for a computer program to run the tests so that I do not repeat myself.
how to run the tests automatically
I can use pytest-watch to run tests automatically. It is a Python program that automatically runs pytest any time a Python file changes in the folder it is looking at, this means it will run the tests for me every time I make a change.
pytest is a Python package like unittest, it is not part of the Python standard library
I type it in the terminal
pytest-watch
the terminal shows
command not found: pytest-watch
I need to install pytest-watch for the computer to use it. Next, I set up a virtual environment to keep programs my project needs in one place
what is a virtual environment?
I can install pytest-watch globally (for the entire computer), which means it will always be available to any project on the computer, but a better way would be to put it in a virtual environment so that it is installed only for this project.
A virtual environment is a separate folder where I can install Python packages that my project needs. This helps me keep things that belong to the project in one place, separate from other things on the computer.
It means I can have a separate virtual environment for every project with only the programs that the project needs. This helps if I decide to package the program to send to someone else, because everything needed by the project is in one place.
how to make a virtual environment
I make a virtual environment with the venv module from the Python standard library
python3 -m venv .venvthe terminal goes back to the command line
python3is the Python program-mis an option passed to Python to run the module given after the optionvenv is a module from the Python standard library, it is used to make a virtual environment with a given name
.venvis the name I am giving for this virtual environmentImportant
.venvis Python convention, I can use any name I want for the virtual environment
I run tree
tree -L 2the terminal shows
. ├── src │ └── magic.py └── tests ├── __init__.py ├── __pycache__ └── test_magic.pyit does not look like anything changed. This is because the
.in front of.venvmeans the folder is hiddenI try tree again with another option to see what changed
tree -a -L 2the terminal shows
. ├── src │ └── magic.py ├── tests │ ├── __init__.py │ ├── __pycache__ │ └── test_magic.py └── .venv ├── bin ├── .gitignore ├── include ├── lib ├── lib64 -> lib └── pyvenv.cfgthere is now a folder named
.venvfor the virtual environment
how to activate a virtual environment
When I want to work in a virtual environment, I make sure I am in the parent directory of it, for example,
magicin this case. I activate the virtual environment in the terminal to use itsource .venv/bin/activatethe terminal shows
(.venv) .../magic $the
(.venv)on the far left of the command line in the terminal shows that I am in the virtual environmentI use pytest-watch to run the test again
pytest-watchthe terminal shows
command not found: pytest-watchI have to install pytest-watch in the virtual environment to use it in the virtual environment
how to see what packages are installed in a virtual environment
I use the Python package manager (pip) to see what Python packages are installed in the virtual environment I just made
pip list
the terminal shows
Package Version
------- -------
pip x.y
pytest-watch is not in the list
pip is a module from the Python standard library, it is used to install Python packages
how to write text to a file
I want to make a file where I can list all the Python packages for my project as a way to document it and have pip install the programs listed in the file
I can write text to a file with the echo program, it shows whatever it is given as an argument, on the screen (standard output (stdout)) for example
echo "pytest-watch"the terminal shows
pytest-watchI can also use echo to add text to a file, I use it to make the requirements file with pytest-watch as what is inside it
echo "pytest-watch" > requirements.txt>is an operator that is used to send output from a program to the given filepytest-watch is a Python program that automatically runs pytest when a Python file in the folder changes
pytest is a Python package like unittest, that is used for testing
requirements.txtis the name of a file where I can list Python packages for pip to install. The namerequirements.txtis Python convention, I can use any name I want for the requirements file
I run tree to see what the project looks like now
tree -a -L 2the terminal shows
. ├── requirements.txt ├── src │ └── magic.py ├── tests │ ├── __init__.py │ ├── __pycache__ │ └── test_magic.py └── .venv ├── bin ├── .gitignore ├── include ├── lib ├── lib64 -> lib └── pyvenv.cfgrequirements.txtis now in themagicfolder
how to see what is inside a file
I can use the cat program to see what is inside a file. I use it to make sure my requirements.txt has pytest-watch inside it
cat requirements.txt
the terminal shows
pytest-watch
life is good!
how to install Python packages in a virtual environment
I use pip to install pytest-watch from the requirements file
python3 -m pip install --requirement requirements.txt--requirementis an option that can be given to theinstallargument for Python packages in a given filerequirements.txtis the name of the given file
the terminal shows programs being downloaded and installed, and when I do not have the latest version of pip installed, it shows this at the end
[notice] A new release of pip is available: XY.Z -> AB.C [notice] To update, run: pip install --upgrade pip
how to upgrade the Python package manager in a virtual environment
I upgrade pip to the latest version. I recommend you do this every time you are in a virtual environment, it is good practice to update package managers to the latest version available
python3 -m pip install --upgrade pippip is a module from the Python standard library, it is used to install Python packages
installis an argument given to pip to install a given Python package--upgradeis an option that can be passed to theinstallargument, like--requirementfrom earlier, this one tells pip to upgrade the version of the given Python packagepipis the Python package I am giving pip to install, in this case it upgrades itself to the latest version since I did not give a version number
the terminal shows
... Installing collected packages: pip Attempting uninstall: pip Found existing installation: pip XY.Z Uninstalling pip-XY.Z: Successfully uninstalled pip-XY.Z Successfully installed pip-AB.CNote
I can also tell pip to install pytest-watch directly without using a requirements file, the problem is it will not document what programs my project needs. I would either have to remember later or use
pip list. It also does not help someone else who is trying to run my project later, know what programs it needs without mepython3 -m pip install pytest-watchI check what Python packages are now installed in the virtual environment
pip listthe terminal shows
Package Version ------------ ------- colorama x.y.z docopt x.y.z iniconfig x.y.z packaging x.y pip x.y pluggy x.y.z Pygments x.y.z pytest x.y.z pytest-watch x.y.z watchdog x.y.zpytest-watch is in the list. Yes!
Tip
imagine that the pytest-watch project also has a requirements file with
colorama,docopt,iniconfig,packaging,pluggy,Pygments,pytestandwatchdogas programs that it needs to run and they got installed when I asked pip to install pytest-watch from therequirements.txtfile
how to run the tests automatically in a virtual environment
I try to run the tests again
pytest-watch
and it shows results without going back to the command line
================== test session starts===================
...
rootdir: .../magic
collected 1 item
tests/test_magic.py . [100%]
=============== 1 passed in X.YZs =======================
how to open the test file in the editor from the terminal
I hold ctrl (Windows/Linux) or option or command (MacOS) on the keyboard and click on
tests/test_magic.pyto place the cursor in the editor of the Integrated Development Environment (IDE), then I change False to True on line 77 self.assertFalse(True)the terminal shows AssertionError
====================================== FAILURES ======================================= _______________________________ TestMagic.test_failure ________________________________ self = <tests.test_magic.TestMagic testMethod=test_failure> def test_failure(self): > self.assertFalse(True) E AssertionError: True is not false tests/test_magic.py:7: AssertionError ============================== short test summary info ================================ FAILED tests/test_magic.py::TestMagic::test_failure - AssertionError: True is not false ================================= 1 failed in X.YZs ===================================I hold ctrl (Windows/Linux) or option or command (MacOS) on the keyboard and click on
tests/test_magic.py:7to place the cursor in the editor of the Integrated Development Environment (IDE), then I change True back to False intest_magic.py7 self.assertFalse(False)the test passes and I can write the rest of the code for the project as the tests run automatically in response to any change I make
how to stop the automated tests
I exit the tests in the terminal with ctrl+c on the keyboard
how to deactivate a virtual environment
I leave the virtual environment by typing this in the terminal
deactivatethe terminal goes back to the command line,
(.venv)is no longer on the left side.../pumping_python/magicI try pytest-watch again to show that I do not have it installed outside the virtual environment
pytest-watchthe terminal shows
command not found: pytest-watchI change directory to the parent of
magiccd ....is shorthand for the parent of any directory you are in. The terminal shows.../pumping_pythonI am back in the
pumping_pythonfolder
review
I gave the computer some commands to make a Python Test Driven Development environment. I made some folders and files, successfully wrote a failing test, made it pass, then made the tests run automatically
how to view all the commands I typed in a terminal
I type history in the terminal to see all the commands I have typed so far
historythe terminal shows
cd pumping_python mkdir pumping_python cd pumping_python tree sudo apt install tree --yes tree cd magic mkdir magic tree cd magic python3 src/magic.py mkdir src tree python3 src/magic.py touch src/magic.py tree python3 src/magic.py python3 -m unittest mkdir tests tree touch tests/magic.py tree python3 -m unittest touch tests/__init__.py tree python3 -m unittest mv tests/magic.py tests/test_magic.py tree -L 2 python3 -m unittest pytest-watch python3 -m venv .venv tree tree -a -L 2 source .venv/bin/activate pytest-watch pip list echo "pytest-watch" echo "pytest-watch" > requirements.txt tree -a -L 2 cat requirements.txt python3 -m pip install --requirement requirements.txt python3 -m pip install --upgrade pip pip list pytest-watch deactivate pytest-watch cd .. touch makePythonTdd.sh tree -a -L 2the history program shows all the commands I typed in the terminal so far, and I use them to write the program that will automatically make a Python Test Driven Development environment for me
these are the commands I used to help make a Python Test Driven Development environment
mkdir NAME_OF_THE_PROJECT cd NAME_OF_THE_PROJECT mkdir src touch src/NAME_OF_THE_PROJECT.py mkdir tests touch tests/__init__.py touch tests/test_NAME_OF_THE_PROJECT.py python3 -m venv .venv source .venv/bin/activate echo "pytest-watch" > requirements.txt python3 -m pip install --upgrade pip python3 -m pip install --requirement requirements.txt pytest-watchwhere
NAME_OF_THE_PROJECTis the name I give the projectthese are the steps I took to make a Python Test Driven Development environment
pick a name for the project
make a Python file to hold the source code in the ‘src’ folder
make the test pass
How many questions can you answer after going through this chapter?
what is next?
You have seen me make a Test Driven Development environment for a project called magic on any Linux, Windows with Windows Subsystem for Linux or MacOS computers. Would you like to test AssertionError next?
rate pumping python
If this has been a 7 star experience for you, please leave a 5 star review. It helps other people get into the book too