> For the complete documentation index, see [llms.txt](https://furkhan324.gitbook.io/workspace/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://furkhan324.gitbook.io/workspace/dev/python/unit-testing.md).

# Unit Testing

### Structure

We use python's built-in vanilla unittest module to write tests. For most use cases, this package provides us with sufficient tools to get the job done

Example unit test folder structure

```
/src
    /packageA
        - A.py
    /tests
        /packageA
             - test_A.py
    run_tests.py
```

In general, we want the directory that holds the tests to be of the same structure as the packages and modules we intend to test (i.e packageA).

#### TestCase

The smallest unit of testing is an instance of unittest.TestCase. This represents a single test case/or a few closely related ones.

{% code title="test\_A.py" %}

```python
from packageA.A import A
import unittest

class TestA(unittest.TestCase):
    def setUp(self):
        ... # Code runs before each test_* is executed
        
    def test_A_like_this(self):
        ... # Write asserts here
        
    def test_A_like_this_too(self):
        ... # Write asserts here too
    
    def tearDown(self):
        ... # Code runs after each test_* is executed

if __name__ == 'main':
    # Runs all test cases within this module
    unittest.main()    
```

{% endcode %}

Some pointers:

* setUp & tearDown are called before & after each test method is called. (Called each time for each test\_\* method)
* test methods must be of the form test\_\* to be run by unittest
* A unittest.TestCase can also implement runTest as opposed to test\_\* methods if it is only implementing one test

#### Discovery (TestLoader)

We can group multiple TestCases together into TestSuites and run them (This is usually what we want to do). We want to write unittests without having to worry to import and run them as well. TestLoaders make this very easy.

The unittest.TestLoader has a discover method that auto-detects TestCases within a directory and adds them all to a suite.&#x20;

Let's assume that our folder structure looks like this:

```
/src
    /packageA
        - A.py
    /tests
        - __init__.py
        /packageA
             - __init__.py
             - test_A.py
    run_tests.py
```

We can load and run all tests within the /tests directory from run\_tests.py in the following manner:

{% code title="run\_tests.py" %}

```python
import unittest

# Provide top_level_dir otherwise unittest changes sys.path messing up imports
suite_with_all_tests = unittest.defaultTestLoader.discover('./tests', top_level_dir='.')

runner = unittest.TextTestLoader()
runner.run(suite_with_all_tests)
```

{% endcode %}

Some pointers about TestLoader:

* If you want to define your own way to search for test\_cases you can make your own TestLoader that overrides discover
* discover() under the hood looks for load\_tests to be defined within \_\_init\_\_ files or the modules. More here: <https://docs.python.org/2/library/unittest.html#test-discovery>
* modules that house Test\_Cases must be named test\_\*.py
* **Directories & subdirs to be searched must have \_\_init\_\_.py files**. discover seems to not work well with Implicit Namespace Packages. See this: <https://stackoverflow.com/questions/46976256/recursive-unittest-discovery-with-python3-and-without-init-py-files>
* **top\_level\_dir should be passed in as '.'.** Otherwise it sets the start\_dir as the top\_level\_dir, adds this to sys.path and can mess up imports across the app
