how to make a python test driven development environment


This is one way to make a Python Test Driven Development environment


requirements

windows requirements

If you are using a Windows computer, try

linux/Windows Subsystem Linux requirements

Open a terminal then type this to update the Linux package manager

sudo apt update

type this in the terminal to install Python

sudo apt install python3 python3-venv --yes

how to manually make a python test driven development environment

  • Imagine I have to work on a project and it’s name is magic. I open a terminal in the Integrated Development Environment (IDE) and use mkdir

    mkdir magic
    

    this makes a folder/directory for the project where its files will stay

  • I use cd

    cd magic
    

    this changes directory to the magic folder/directory I just made

  • I make a child folder/directory for the source code (the actual program)

    mkdir src
    

    I use touch to make an empty file

    touch src/magic.py
    

    this adds an empty file for the source code (the actual program)

  • I make a child directory

    mkdir tests
    

    this is where I will add tests for the project

  • I use touch to add an empty file called __init__.py in the tests folder

    Attention

    make sure to use 2 underscores (__) for __init__.py

    touch tests/__init__.py
    

    this tells Python that tests is a python package, it will help it find the tests I write later

  • I use touch to add one more empty file in the tests directory for the actual test

    touch tests/test_magic.py
    

    Tip

    I can use any name for the file as long as it starts with test_

  • these are the folders/directories and files in the project

    magic
      ╰──src
      |  ╰──magic.py
      ╰──tests
         ╰──__init__.py
         ╰──test_magic.py
    

    .py at the end of a file name shows it is a Python module


test_failure

The Test Driven Development cycle is RED GREEN REFACTOR

  • RED: make it fail - write a failing test to make sure the test works

  • GREEN: make it pass - write only what is needed to make the failing test pass

  • REFACTOR: make it better - remove duplication

red: make it fail

  • I click on magic/tests/test_magic.py in the Integrated Development Environment (IDE) to open it in the editor, then type the following

    Note

    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 in the file

  • I turn on the Auto Save feature in the Integrated Development Environment (IDE) to automatically save files when I make a change so I do not repeat myself by having to hit save (ctrl+s) every time I make a change

  • I type this in the terminal to run the test

    python3 -m unittest
    

    the terminal shows AssertionError

    F
    =============================================================
    FAIL: test_failure (tests.test_magic.TestMagic.test_failure)
    -------------------------------------------------------------
    Traceback (most recent call last):
    File ".../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)
    

If you are typing along, CONGRATULATIONS! You just wrote a test.

This is the RED part 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

  • FAILED (failures=1) the number of failures

  • Ran 1 test in A.XYZs the number of tests it ran and how long they took

  • AssertionError: True is not false the Error/Exception raised and its message, in this case AssertionError is raised because True is not False

  • self.assertFalse(True) the line of code that caused the failure

  • File ".../magic/tests/test_magic.py", line 7, in test_failure the line number of the code that caused the failure and the location of the file where it is

    Tip

    Hold ctrl (windows/linux) or option (mac) on the keyboard and use the mouse to click on File ".../magic/tests/test_magic.py", line 7 in the terminal, and the Integrated Development Environment (IDE) will open the file in the editor with the cursor at the line where the failure happened

  • Traceback (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

  • FAIL: test_failure (tests.test_magic.TestMagic.test_failure) is a header with information in dot notation about the failing test method

    • tests.test_magic.TestMagic.test_failure is the location of the failing test

    • tests is the tests folder

    • test_magic is the test_magic.py file

    • TestMagic is the class defined on line 4

    • test_failure is the method defined on line 6

  • F shows a failure

  • python3 -m unittest is the command to run tests with the unittest module

    • python3 is the Python program

    • -m is an option/switch passed to Python to run the module given after it

  • I recommend you keep a list of Errors/Exceptions you meet to become familiar with them, it helps when you run into failures later. I add AssertionError to the list

     1import unittest
     2
     3
     4class TestMagic(unittest.TestCase):
     5
     6    def test_failure(self):
     7        self.assertFalse(True)
     8
     9
    10# Exceptions Encountered
    11# AssertionError
    

green: make it pass

I change the input on line 7 from True to False

self.assertFalse(False)

then I run the test again in the terminal

python3 -m unittest

and the test passes

.
------------------------------------------------------
Ran 1 test in A.XYZs

OK

cue CELEBRATION MUSIC AND DANCE! I am GREEN.

refactor: make it better

I ran python3 -m unittest to see the test fail, I ran it again to see the test pass. I will have to run it again when I make a code change, to make sure tests that were passing are not failing and that the new code I added does what I expect.

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 program to run the tests so I do not repeat myself.


how to automatically run tests

how to make a virtual environment

  • I make a virtual environment with the venv module

    python3 -m venv .venv
    
  • I activate the virtual environment to use it

    source .venv/bin/activate
    

    the (.venv) on the far left of the command line in the terminal shows that I am in the virtual environment, for example

    (.venv) .../magic $
    
  • I upgrade pip the python package manager to the latest version

    python3 -m pip install --upgrade pip
    
    • pip is a module from the python standard library, it is used to install python packages

    • install is an argument given to pip to install a given package name

    • --upgrade is an option/switch given to the install argument for pip to upgrade the version of the python package given

    • pip is the package name I am giving pip to install, in this case it upgrades itself

  • I use pip to see what packages are installed in the virtual environment

    pip list
    

    the terminal shows

    Package Version
    ------- -------
    pip     x.y
    
  • I use echo to make a file in the magic directory with pytest-watch as its text

    echo pytest-watch > requirements.txt
    
  • I install pytest-watch and the programs it needs

    pip install --requirement requirements.txt
    
    • --requirement is another option that can be passed to the install argument for python packages in a given file

    • requirements.txt is the name of the file given

      Note

      requirements.txt is Python convention, I can use any name I want

  • I use pip to see what packages are now installed in the virtual environment

    pip list
    

    the 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.z
    
  • The folder/directory structure now looks like this

    magic
      ╰──.venv
      ╰──src
      | ╰──magic.py
      ╰──tests
      |  ╰──__pycache__
      |  ╰──__init__.py
      |  ╰──test_magic.py
      ╰──requirements.txt
    
  • I run the tests from the terminal

    pytest-watch
    

    and it shows results without going back to the command line

    [TODAYS_DATE] Running: py.test
    ================== test session starts===================
    ...
    rootdir: .../magic
    collected 1 item
    
    tests/test_magic.py .                              [100%]
    
    =============== 1 passed in X.YZs =======================
    
  • when I change the input on line 7 in test_magic.py from False to 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 change True back to False in test_magic.py to make it pass. I can now write the rest of the code for the project while the tests run automatically

    Tip

    press ctrl + c on the keyboard in the terminal to stop the tests at anytime


how to deactivate a virtual environment

When I want to leave a virtual environment, I type this in the terminal to deactivate it

deactivate

how to activate a virtual environment

When I want to work in a virtual environment, I change directory to the folder/directory that has the virtual environment for example magic, and type this in the terminal

source .venv/bin/activate

the (.venv) on the far left of the command line in the terminal shows that I am in the virtual environment, for example

(.venv) .../magic $

how to automatically make a python test driven development environment

You made it this far and have become the greatest programmer in the world. To follow The Do Not Repeat Yourself (DRY) Principle, I write a program that has all the commands it took to get here, then I can use it to make a Test Driven Development Environment anytime I want and not have to remember every step of the process

  • I exit the tests in the terminal by pressing ctrl + c on the keyboard

  • I leave the virtual environment

    deactivate
    
  • I use cd to change directory to the parent of magic

    cd ..
    
  • I use touch to make an empty file with a name that describes what the program does so it is easy to remember later, for example makePythonTdd.sh

    touch makePythonTdd.sh
    
  • I use the history program

    history
    

    the terminal shows all the commands I have typed so far, and I use them to write the program

  • I click on makePythonTdd.sh to open it in the Integrated Development Environment (IDE), then type the commands I need to make a Test Driven Development Environment in the editor

    Note

    the line numbers below are a guide, you do not need to copy them

     1#!/bin/bash
     2mkdir magic
     3cd magic
     4mkdir src
     5touch src/magic.py
     6mkdir tests
     7touch tests/__init__.py
     8touch tests/test_magic.py
     9python3 -m venv .venv
    10source .venv/bin/activate
    11python3 -m pip install --upgrade pip
    12echo pytest-watch > requirements.txt
    13python3 -m pip install --requirement requirements.txt
    14pytest-watch
    

    #!/bin/bash is a shebang line that tells the computer to use bash to run the program

  • The problem with this program is it will always make a project called magic. I need it to be able to make any project I want. I add a variable to replace magic so I can give it any name when I want to make a project

    Note

    the line numbers below are a guide, you do not need to copy them

     1#!/bin/bash
     2PROJECT_NAME=$1
     3mkdir $PROJECT_NAME
     4cd $PROJECT_NAME
     5mkdir src
     6touch src/$PROJECT_NAME.py
     7mkdir tests
     8touch tests/__init__.py
     9touch tests/test_$PROJECT_NAME.py
    10python3 -m venv .venv
    11source .venv/bin/activate
    12python3 -m pip install --upgrade pip
    13echo pytest-watch > requirements.txt
    14python3 -m pip install --requirement requirements.txt
    15pytest-watch
    

    $1 is for the first argument given when the program is called, I can use it in place of $PROJECT_NAME for example

    command argument
    

    in the code above, command will be makePythonTdd.sh and $1 will get the value of argument

  • I use the echo program to add text for the first failing test to test_$PROJECT_NAME.py

     1#!/bin/bash
     2PROJECT_NAME=$1
     3mkdir $PROJECT_NAME
     4cd $PROJECT_NAME
     5mkdir src
     6touch src/$PROJECT_NAME.py
     7mkdir tests
     8touch tests/__init__.py
     9
    10echo "import unittest
    11
    12
    13class Test$PROJECT_NAME(unittest.TestCase):
    14
    15    def test_failure(self):
    16        self.assertFalse(True)
    17
    18
    19# Exceptions Encountered
    20# AssertionError
    21" > tests/test_$PROJECT_NAME.py
    22
    23python3 -m venv .venv
    24source .venv/bin/activate
    25python3 -m pip install --upgrade pip
    26echo pytest-watch > requirements.txt
    27python3 -m pip install --requirement requirements.txt
    28pytest-watch
    
  • I type this in the terminal to make sure the program I just wrote is executable

    chmod +x makePythonTdd.sh
    

    chmod is a program that changes the mode of the given file

  • I can make a Test Driven Development environment when I call the program with a name for the PROJECT_NAME variable. For example, when I type this in the terminal in the folder where makePythonTdd.sh is saved,

    ./makePythonTdd.sh calculator
    

    the computer will make a Test Driven Development environment for a project called calculator, you can continue this in how to make a calculator


review

One of the advantages of programming is that I can take some steps and make them a one line command for the computer to do for me.

You have seen a way to make a Python Test Driven Development Environment, and have a program to do it for you on any Linux, Windows or MacOS computers.

Would you like to test making a calculator?


makePythonTdd.sh