Codementor Events

Test-Driven Development with PyTest - Part 2

Published Dec 08, 2019Last updated Jun 04, 2020
Test-Driven Development with PyTest - Part 2

Introduction

Welcome back to part 2 of the test-driven development with PyTest.

For part two of the TDD with Pytest.

I would be covering the project structure where your test cases will reside.

The creation of test cases as a class or function under pytest.

Do head to part 1 of the series before proceeding with part 2.

It is assumed that a Linux system is used for this series.

Please use a Linux variant like Ubuntu or a cloud IDE like Codenvy running a Linux virtual container.

Project Structure

Whenever you are creating test cases for your Python program.

There are the various school of thoughts on this for the location you will be putting your test cases in.

Your test cases could either reside within the program's subdirectories you are testing or create a centralized directory which your test cases reside in.

Some pros and cons come with it. It is a matter of project preference that is set by the development & QA team.

For me, I would prefer a centralized location for my test cases under ** tests** directory.

As it reduces the amount of time that a developer has to hunt and test out the various program components.

If you had read Python Testing with Pytest by Brian Okken.

He did a combination of both for bite-sized consumption in each chapter and putting the test cases under specific test directory.

Therefore going through his book will allow you to consider which will be a better choice for you.

You could access the book's source code and use the book as a reference guide to help you learn about Pytest in Python.

Create Test Cases as Class or Function

When you are just starting to learn to create test cases using Pytest.

We start by embedding a test case function to the program:

Embedded Test Case as Function

Create a file called tutorial.py and with a test_input function:

touch tutorial.py

tutorial.py
'''python
a = 0
b = 0

def test_input():
assert a >= 0
assert b >= 0

'''
Now run the following command in your own terminal.

pytest tutorial.py

pytest 1

This is an example of creating your test cases as a function.

When a file has more than a certain amount of lines. It has to be separated for ease of maintainability.

Test cases in a Separate File

Now refactor this test case into a separate file called test_tutorial.py which was created during part 1 of the series:

test_tutorial.py

import tutorial


def test_input():
    a = tutorial.a
    b = tutorial.b

    assert a >= 0
    assert b >= 0

Now execute the previous command.

pytest test_tutorial.py

pytest 2

Besides importing the tutorial.py and adding variable declaration as part of the function.

Test Cases in a Class

Classes are commonly used as a way to store multiple test cases under a specific feature or part of the program.

The reason for it is to allow testing of a specific part of the program.

Without another feature to interfere with your test cases that might lead to an inaccurate test result.

Now, let us refactor the previous function test case into a class function called TestInput:

import tutorial


class TestInput:
    def test_a_input(self):
        a = tutorial.a

        assert type(a) != float
        assert a >= 0

    def test_b_input(self):
        b = tutorial.b

        assert type(b) != float
        assert b >= 0

Now let us run the pytest command with the -v (verbose) option enabled on the newly refactored class test case.

pytest -v test_tutorial.py

pytest 3

You should have two test cases which are test_a_input & test_b_input under TestInput.

Now for this TestInput class is used to test the input parameters of the program called tutorial.py.

We could create and test the function in the tutorial.py called getsum which calculates the result of parameter a and b as another class:

tutorial.py

a = 0
b = 0


def getsum(a, b):
    return a + b

test_tutorial.py

import tutorial


class TestInput:
    def test_a_input(self):
        a = tutorial.a

        assert type(a) != float
        assert a >= 0

    def test_b_input(self):
        b = tutorial.b

        assert type(b) != float
        assert b >= 0


class TestGetSum:
    def test_addition(self):
        assert tutorial.getsum(2, 8) == 10

Now let us run the following command, which results with 3 test cases under 2 classes.

pytest -v test_tutorial.py

pytest 4

Imagine you could enhance it further by creating multiple test cases within each class. That is the reason why having a test case as a class is useful for maintainability purposes and separation of concern.

Conclusion

I hope this article provides you with an understanding of how your test cases should reside for the project structure.

Along with the understanding of the difference creating test cases as a function or class for PyTest.

Do note that the next part of the series, I will show my attempt to use a PyTest for a code kata exercise to demonstrate your understanding of PyTest.

If you like my article, please sign up for Max Adventurer's Newsletter for awesome content I stumble across weekly in Python, Startup and Web Development.

You can also follow me to get the latest update of my article on CodeMentor

This post was originally posted on Max's blog at Test-Driven Development With PyTest - Part 2: Reading Time 4 Mins and Photo by Joyce McCown on Unsplash

References

Discover and read more posts from Max Ong Zong Bao
get started
post comments5Replies
Abood Ghazal
5 years ago

My biggest issue with TDD is I use pandas dataframe a lot and it can be tedious to setup those test in the pytest annotation.

Max Ong Zong Bao
5 years ago

Not really it depends on your understanding of how TDD works. I’m not really that strict which could be just unit tests and you slowly refactor it into integration test.

It can be as simple as this for the unit tests.

  • Checking for input path if file exists

  • Checking for empty input data after reading data

  • Checking number of columns for input data

  • Checking if columns have the correct column names for input data

  • Checking for input data type

  • Checking for empty output data

  • Checking for output data type

  • Checking number of columns for output data

  • Checking if columns have the correct column names for output data

My suggestions are to go for coding dojos in your area which encourages pair programming and work on code katas.

Abood Ghazal
5 years ago

My biggest issue with TDD is I use pandas dataframe a lot and it can be tedious to setup those test in the pytest annotation.

https://snaptube.cam/ , https://syncnet.onl/telegram-web/

Brodie Foran
5 years ago

Yeah, it`s really cool!

Max Ong Zong Bao
5 years ago

Thanks a lot I’m glad that it is useful to you :)

Show more replies