Python Testing Framework
Tags: python, testing, devops, beginners
Published: 2020-09-11 13:00:47

The original post was on [Python Testing Framework - Reading Time: 3 Mins](https://www.maxongzb.com/python-testing-framework-reading-time-3-mins/) and cover image by [Photo by David Travis on Unsplash](https://unsplash.com/photos/WC6MJ0kRzGw)

# Introduction
Testing can be a pain. It is painful to write test cases. Without it, doing manual testing **sucks** the life out of you. This makes it worst when you had to remember every single command and steps that could take hours to do it. 

I know the **importance** of delivery when you are on a **time crunch** & **death march** to get it done. But... if your spending tons of effort to test your deployment. You are **sabotaging** yourself as these could be [automated][1]. Which frees up your time to make changes to your code to make it better, faster and maintainable for your future self or teammates who will be maintaining it.

# Unittest
This is the [default testing framework][2] that comes with Python whenever you install Python in your development environment. I won't be introducing alot of it. As you learn about Java, it draws inspiration from [JUnit][3]. 

I found that one big **grumble** that I had with the default framework that is bundled with Python. It is **boilerplate code** when you are creating test cases. Look at this example of a test case which is enough for me to stop learning it. Due to the amount of **boilerplate** code to write it to test my code:

```python
import unittest

class TestStringMethods(unittest.TestCase):

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FOO')

    def test_isupper(self):
        self.assertTrue('FOO'.isupper())
        self.assertFalse('Foo'.isupper())

    def test_split(self):
        s = 'hello world'
        self.assertEqual(s.split(), ['hello', 'world'])
        # check that s.split fails when the separator is not a string
        with self.assertRaises(TypeError):
            s.split(2)

if __name__ == '__main__':
    unittest.main()
```

# Pytest
[Pytest][4] is still my **goto** testing framework. What I love about Pytest. It is the **ease** to get started with it and without tons of boilerplate to make it work.:

```python
# From the previous example of the unit test but in Pytest

def test_upper():
    assert 'foo'.upper() == "FOO"

def test_isupper():
        assert 'FOO'.isupper() == True
        assert 'Foo'.isupper() == False

def test_split():
	s = 'hello world'

	assert s.split == ['hello', 'world']
	assert type(s.split(2)) == str
```

With an evergrowing list of goodies. Like the [Markers][5] for executing specific test cases. Along with [Fixtures][6] to make testing consistent with a foundation to start from.

This allows you to create **smoke test** to get a rough understanding of your program. Not forgetting [PyCharm][7] **Professional** edition makes it easy to **automate** and do [Test Driven Development (TDD)][8]. Which is part of the reason that I would still stay with PyCharm due to the number of things I like about them.

# Behave 
[Behave][9] that focus on doing [Behavour Driven Development (BDD)][10] is something that I had yet to try.

But in layman terms, it is framing your test cases into user stories using the [Given-When-Then][11]~tags~(~'given*20when*20then))~searchTerm~'~sort~false~sortDirection~'asc~page~1)) formula. This allows **ease of understanding** for the **context** in your test cases for anyone be it a designer, product owner or a developer. As your frame your user stories into test cases using that formula.

Currently, I do not need it for my work. But I gained more insights, when I was reading [The Pragmatic Programmer][12]. Which gave me the **perspective** to combined it with TDD practices to form a **dragnet**. 

To test out various scenarios as a test case. Which once a bug has been found. You patch your program and create a unit test to catch the bug from ever occurring again in the future.  

# Conclusion
I had outlined the need for writing test cases to **automate** the testing process so that it frees you to focus on higher-value work. Like writing documentation, improving your CI/CD pipeline or even pair programming with your junior developer to speed up their learning process.

I had also covered the 3 python testing frameworks. That I know namely **unittest** that comes with Python. **PyTest** which is one of my favourite testing frameworks. **behave** that focus on the use of **BDD** to create test scenarios from user stories using the **Give When Then** formula.

Lastly, are you looking to specialise yourself as a developer? If it's a Yes. I'm giving away my free ebook called ["Picking Your Specialisation as a Developer"](https://maxongzb.activehosted.com/f/5) for anyone interested to command a higher salary or do the work that you like.

This post includes affiliate links, I may receive compensation if you purchase products or services from the different links provided in this article.

# Reference
* [5 Reasons for Automated Testing][1]
* [Python Default Testing Framework][2]
* [Pytest][4] 
* [Markers][5]
* [Fixtures][6]
* [PyCharm][7]
* [Test Driven Development (TDD)][8]
* [Behave][9]
* [Behavour Driven Development (BDD)][10] 
* [JUnit][3]
* [The Pragmatic Programmer][12]
* [Getting Started with Python Testing][13]
* [Pytest][14]
* [Behave][15]
* [Python Testing with Pytest][16]
* [Architecture Patterns with Python: Enabling Test-Driven Development, Domain-Driven Design, and Event-Driven Microservices][17]


[1]: https://rollout.io/blog/5-reasons-for-automated-testing/
[2]: https://docs.python.org/3/library/unittest.html
[3]: https://junit.org/junit5/
[4]: https://docs.pytest.org/en/stable/contents.html
[5]: https://docs.pytest.org/en/stable/example/markers.html
[6]: https://docs.pytest.org/en/stable/fixture.html
[7]: https://www.jetbrains.com/pycharm/
[8]: https://www.freecodecamp.org/news/learning-to-test-with-python-997ace2d8abe/
[9]: https://behave.readthedocs.io/en/latest/tutorial.html
[10]: https://www.agilealliance.org/glossary/bdd/
[11]: https://www.agilealliance.org/glossary/gwt/#q=~(infinite~false~filters~(postType~(~'page~'post~'aa_book~'aa_event_session~'aa_experience_report~'aa_glossary~'aa_research_paper~'aa_video
[12]: https://amzn.to/3k2MtoQ
[13]: https://realpython.com/python-testing/
[14]: https://docs.pytest.org/en/stable/
[15]: https://behave.readthedocs.io/en/latest/
[16]: https://amzn.to/325EAIZ
[17]: https://amzn.to/3lQwITA