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

Attention

Do this only if you are using Linux or Windows Subsystem Linux

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 its 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

    touch src/magic.py
    

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

  • I make a child folder/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 test 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 hitting save (ctrl+s (windows/linux) or command+s (mac)) every time

  • 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

  • ~~~~~~~~~~~~~~~~^^^^^^ points to the part of the line above it that it thinks caused the error

  • 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, this is why I like to read it from the bottom up

  • 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 them 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! The terminal shows

.
------------------------------------------------------
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 python3 -m unittest again to see the test pass. I will have to run python3 -m unittest again when I make a code change, to make sure tests that were passing are not failing and that the new code I add 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
    
    • python3 is the Python program

    • -m is an option passed to Python to run the module given after the option as a script

    • venv is a module from the python standard library, it is used to make a virtual environment with a given name.

    • A virtual environment is a separate folder where python packages needed by the project will be installed, this helps me keep things that belong to the project in one place separate from other things on the computer

    • .venv is the name given

      Note

      .venv is Python convention, I can use any name I want for the virtual environment

  • 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 given python package

    • 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 for the file

  • 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
    
  • I now have these folders/directories and files in the project

    magic
    ├── .venv
    ├── src
    │   └── magic.py
    └── tests
    │   ├── __init__.py
    │   ├── __pycache__
    │   └── 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 when you want to stop the tests


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 history

    history
    

    the history program shows all the commands I have typed in the terminal 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 be 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 can run

    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 terminal shows

    ====================================== FAILURES =======================================
    _____________________________ Testcalculator.test_failure _____________________________
    
    self = <tests.test_calculator.Testcalculator testMethod=test_failure>
    
        def test_failure(self):
    >       self.assertFalse(True)
    E       AssertionError: True is not false
    
    tests/test_calculator.py:7: AssertionError
    =============================== short test summary info ===============================
    FAILED tests/test_calculator.py::Testcalculator::test_failure - AssertionError: True is not false
    ================================== 1 failed in X.YZs ==================================
    

    the computer made 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 test AssertionError?


Click Here to see the code for the program to make a Python Test Driven Development environment for any Linux or MacOS computers