Search code examples
pythonpython-3.xunit-testingpython-unittest

Python unittests used in a project structure with multiple directories


I need to use unittest python library to execute tests about the 3 functions in src/arithmetics.py file. Here is my project structure.

.
├── src
│   └── arithmetics.py
└── test
    └── lcm
        ├── __init__.py
        ├── test_lcm_exception.py
        └── test_lcm.py

src/arithmetics.py

def lcm(p, q):
    p, q = abs(p), abs(q)
    m = p * q
    while True:
        p %= q
        if not p:
            return m // q
        q %= p
        if not q:
            return m // p

def lcm_better(p, q):
    p, q = abs(p), abs(q)
    m = p * q
    h = p % q
    while h != 0:
        p = q
        q = h
        h = p % q
    h = m / q
    return h

def lcm_faulty(p, q):
    r, m = 0, 0
    r = p * q
    while (r > p) and (r > q):
        if (r % p == 0) and (r % q == 0):
            m = r
        r = r - 1
    return m

test/lcm/test_lcm.py

import unittest
from src.arithmetics import *

class LcmTest(unittest.TestCase):
    def test_lcm(self):
        for X in range(1, 100):
            self.assertTrue(0 == lcm(0, X))
            self.assertTrue(X == lcm(X, X))

        self.assertTrue(840 == lcm(60, 168))
    
    def test_lcm_better(self):
        for X in range(1, 100):
            self.assertTrue(0 == lcm_better(0, X))
            self.assertTrue(X == lcm_better(X, X))
    
        self.assertTrue(840 == lcm_better(60, 168))
    
    def test_lcm_faulty(self):
        self.assertTrue(0 == lcm_faulty(0, 0))
    
        for X in range(1, 100):
            self.assertTrue(0 == lcm_faulty(X, 0))
            self.assertTrue(0 == lcm_faulty(0, X))
    
        self.assertTrue(840 == lcm_faulty(60, 168))

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

test/lcm/test_lcm_exception.py

import unittest
from src.arithmetics import *

class LcmExceptionTest(unittest.TestCase):
    def test_lcm_exception(self):
        for X in range(0, 100):
            self.assertTrue(0 == lcm(0, 0))         # ZeroDivisionError
            self.assertTrue(0 == lcm(X, 0))         # ZeroDivisionError

    def test_lcm_better_exception(self):
        for X in range(0, 100):
            self.assertTrue(0 == lcm_better(0, 0))  # ZeroDivisionError
            self.assertTrue(0 == lcm_better(X, 0))  # ZeroDivisionError
    
    def test_lcm_faulty_exception(self):
        for X in range(1, 100):
            self.assertTrue(X == lcm_faulty(X, X))  # ppcm(1, 1) != 1

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

test/lcm/__init__.py is an empty file

To execute my tests, I tried this command : python3 -m unittest discover

But the output is :

----------------------------------------------------------------------

Ran 0 tests in 0.000s

OK

I don't understand how can I run my tests...

Thanks for helping me !


Solution

  • A file __init__.py is missing

    I think that the problem is the missing of file __init__.py in the folder test. Try to add this (empty) file in that folder as I show you below:

    test_lcm
    ├── src
    │   └── arithmetics.py
    └── test
        └── __init__py    <---------------- add this file
        └── lcm
            ├── __init__.py
            ├── test_lcm_exception.py
            └── test_lcm.py
    

    If you watch my tree folders I have created a folder test_lcm as root of the tree. You have to execute the cd command to place yourself inside that folder.
    So execute a cd command similar to the following (in my system test_lcm is placed in my home folder):

    # go to test_lcm folder
    cd ~/test_lcm
    

    After that, execute:

    # execute test
    python3 -m unittest discover
    

    The last part of the output is:

    ----------------------------------------------------------------------
    Ran 6 tests in 0.002s
    
    FAILED (failures=1, errors=2)
    

    The output shows that are executed 6 tests with 2 errors (test_lcm_better_exception and test_lcm_exception fail).

    Useful links

    • This is a useful link to know how to define a Python package.

    In particular I want to highlight the following sentence present in that link:

    The __init__.py files are required to make Python treat directories containing the file as packages.

    For example, unittest module in standard library doesn't search into directory without __init__.py.

    This explains why the file __init__.py is necessary. May be in the future the unittest module will search tests also in directories without __init__.py file.