Python Unit Testing With Pytest

First, it is hard to write a blog with instructions since I have no idea how much background knowledge you have so please pay attention to these prerequisites:

  • Mac OS X command line and Linux skills
  • PyCharm IDE
  • Python3 knowledge
  • Gitlab for automated test running
  • Good to know conda and concept of virtual environments

Note- I highly suggest using conda ( anaconda ) , since OS X has an old version of python built in (2.7) and it is simpler to use a separate conda environment for development on a Mac.

What you are about to learn is how to use pytest in PyCharm for unit testing. This is as much for my own note keeping as it is to instruct, so I will try to be very thorough.

Install pytest

sudo pip install pytest

Or if using conda, “conda install pytest”

Writing Test Cases

The python file below, which you should name test_example.py, has 3 test cases in it- the functions that start with “test_”. This is a very simple set of test cases. In a real situation you would be importing your python modules and running the functions found in them from your test cases.

# in file test_example.py

# function to test
def capital_case(x):
    return x.capitalize()

# test case that works on outside function
def test_capital_case():
    assert capital_case('semaphore') == 'Semaphore'

# test case that fails (no separate function tested)
def test_failure():
    assert (1 + 3 == 17)

# test case that passes (no separate function tested)
def test_pass():
    assert (1 + 3 == 4)

Running a Test

From the command line

~/PycharmProjects/compression-patton/python$ pytest unittests

Screen Shot 2019-07-23 at 12.40.23 PM

From within PyCharm

You need to create a configuration for running tests. PyCharm has been in support for several test runners, of which pytest (AKA, py.test) is one.

From the Run menu, select Edit Configurations to open the window below. Clicking the ‘+’ will open the context menu where you select Python Tests and then py.test.

Screen Shot 2019-07-23 at 12.43.42 PM

Next, enter the information for the test. You need a name and a target, which is the root folder to look for tests in. In this case, the target is a path to the unittests folder. Any file names that match test_*.py or *_test.py will be examined for test cases (see Test discovery rules) A test case is a python function that starts with “test_”.

Screen Shot 2019-07-23 at 12.42.48 PM

Now you can run your tests from within PyCharm by selecting the correct configuration and pressing the green triangle to run it.

Screen Shot 2019-07-23 at 12.59.25 PM

Did It Work?

There are many moving parts and things don’t always run the first time- the important thing is if you get good output you can interpret and use to fix the error. That is key to any automation system.

In my case, I am using a Gitlab CI Runner to automatically run the unit tests when code is committed (or maybe just once daily). To do this, I needed a special file with instructions that tell the Gitlab CI Runner how to configure itself. It is a standard docker image from docker hub (image name is python:3.7) with extra python modules installed per my instructions.

image: "python:3.7"

before_script:
  - python --version
  - pip install -r requirements.txt

stages:
#  Static Analysis - add this later
  - Test

#flake8:
#  stage: Static Analysis
#  script:

pytest:
  stage: Test
  script:
    -pytest ./python/unittests

(I will be adding more things to this, like static analysis/linting- they are commented out at this time)

Mine did not run at first, but it was great to see the automatic processing take place, with zero effort on my part. As soon as I committed the code and the yaml file, my pipeline ran and attempted to run the unit tests. It failed and sent me an email with great information.

Screen Shot 2019-07-23 at 1.33.35 PM

First, I call “-pytest” instead of just “pytest”. Second, pytest is probably not installed since not in my requirements.txt file (was led to the other modules getting installed as noted in the logs.)

I put my requirements.txt file at the top level of the project.

# this will install these modules using latest version.
pandas
chardet
# just added this
pytest

requirements.txt format will give you all the details on this file

I amended my yaml file, too, by changing the last line to “- pytest ./python/unittests” (yes- the space after the dash is crucial!)

After committing and pushing my changes, the pipeline kicked off again and this time properly ran, albeit one test failed, but that failure was by design so I could see the output.

Screen Shot 2019-07-23 at 1.47.40 PM

I removed the failing test and committed/pushed the changes and the pipeline kicked off again. The pipeline passed as expected.

Screen Shot 2019-07-23 at 1.55.28 PM

When your pipeline passes, you do not get an email but you can check the status of all pipelines at Gitlab.

https://gitlab.com/<yourproject URL>/pipelines

Now on to some real testing!

Some useful links:

https://semaphoreci.com/community/tutorials/testing-python-applications-with-pytest/

https://docs.gitlab.com/ee/ci/README.html

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s