How to run unittest tests from multiple directories - python

I have 2 directories containing tests:
project/
|
|-- test/
| |
| |-- __init__.py
| |-- test_1.py
|
|-- my_submodule/
|
|-- test/
|
|-- __init__.py
|-- test_2.py
How can I run all tests?
python -m unittest discover .
only runs test_1.py
and obviously
python -m unittest discover my_submodule
only runs test_2.py

unittest currently sees project/my_submodule as an arbitrary directory to ignore, not a package to import. Just add project/my_submodule/__init__.py to change that.

Use a test suite file
A possible solution is to write a test suite file as following:
import unittest
from test import test_1
from my_submodule.test import test_2
loader = unittest.TestLoader()
suite = unittest.TestSuite()
suite.addTest(loader.loadTestsFromModule(test_1))
suite.addTest(loader.loadTestsFromModule(test_2))
runner = unittest.TextTestRunner(verbosity=3)
result = runner.run(suite)
Save the previous file in your folder project and call it runner_test.py.
I have written two example test files as following:
project/test/test_1.py
import unittest
class MyTestCase(unittest.TestCase):
def test_1(self):
print("test1")
self.assertEqual("test1", "test1")
if __name__ == '__main__':
unittest.main()
project/my_submodule/test/test_2.py
import unittest
class MyTestCase(unittest.TestCase):
def test_1(self):
print("test1")
self.assertEqual("test1", "test1")
if __name__ == '__main__':
unittest.main()
If you execute the following command:
> cd /path/to/folder/project
> python runner_test.py
The output of previous command (python runner_test.py) is:
test_1 (test.test_1.MyTestCase) ... test1
ok
test_2 (my_submodule.test.test_2.MyTestCase) ... test2
ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK

Related

Problems with relative imports and pytest

I am having an issue whereby relative imports from a .py file within a module are not recognised as such by pytest.
Consider the following directory structure:
.
├── import_pytest_issue
│ ├── __init__.py
│ ├── main.py
│ ├── user.py
│ └── utils.py
└── tests
├── __init__.py
└── test_main.py
main.py, user.py, and utils.py are as follows"
# ./import_pytest_issue/main.py
from user import User
if __name__ == "__main__":
user = User("Fred")
print(f"The user is called {user.name}, and their favourite number is {user.favourite_number}")
# ----------------------------------------------------------------------
# ./import_pytest_issue/user.py
from utils import random_number
class User:
favourite_number = random_number()
def __init__(self, name: str) -> None:
self.name = name
# ----------------------------------------------------------------------
# ./import_pytest_issue/utils.py
from random import choice
def random_number():
return choice(range(1, 11))
...and my test_main.py file is like this:
# ./tests/test_main.py
from import_pytest_issue.user import User
def test_user():
user = User("Larry")
assert user.name == "Larry"
assert user.favourite_number in range(1, 11)
main.py runs without issue:
> python import_pytest_issue/main.py
# The user is called Fred, and their favourite number is 1
...but running pytest I get a ModuleNotFoundError:
> pytest
# ======================================================================== test session starts ========================================================================
# platform linux -- Python 3.10.6, pytest-7.2.1, pluggy-1.0.0
# collected 0 items / 1 error
# ============================================================================== ERRORS ===============================================================================
# ________________________________________________________________ ERROR collecting tests/test_main.py ________________________________________________________________
# ImportError while importing test module 'import-pytest-issue/tests/test_main.py'.
# Hint: make sure your test modules/packages have valid Python names.
# Traceback:
# /usr/lib/python3.10/importlib/__init__.py:126: in import_module
# return _bootstrap._gcd_import(name[level:], package, level)
# tests/test_main.py:1: in <module>
# from import_pytest_issue.user import User
# import_pytest_issue/user.py:1: in <module>
# from utils import random_number
# E ModuleNotFoundError: No module named 'utils'
# ====================================================================== short test summary info ======================================================================
# ERROR tests/test_main.py
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# ========================================================================= 1 error in 0.05s ==========================================================================
FWIW this also happens if I run `python -m pytest`.
Any ideas?

Pytest not able to run test where script A importing another script B in the same folder level as A and giving me ModuleNotFoundError

I am trying to run the unit test using pytest in this project, here main_0.py is importing s3 file.
I am getting ModuleNotFoundError: no module named 's3'
Project Folder Structure
some_project
└───src
├───main
│ └───lambda_function
│ └───some
│ main_0.py
│ s3.py
│
└───test
└───unittest
└───lambda_function
└───some
test_main_0.py
test_s3.py
main_0.py
from s3 import PrintS3
def lambda_handler():
obj = PrintS3()
res = obj.print_txt()
return res
s3.py
class PrintS3:
def __init__(self) -> None:
self.txt = "Hello"
def print_txt(self):
print(self.txt)
return self.txt
test_main_0.py
import unittest
class TestSomeMain(unittest.TestCase):
def test_main_0(self):
from src.main.lambda_function.some.main_0 import lambda_handler
res = lambda_handler()
assert res == "Hello"
test_s3.py is empty.
I also tried adding an empty __init__.py file in both the dir but still the same error
Project Folder Structure after adding __init__.py file
some_project
└───src
├───main
│ └───lambda_function
│ └───some
│ main_0.py
│ s3.py
│ __init__.py
│
└───test
└───unittest
└───lambda_function
└───some
test_main_0.py
test_s3.py
__init__.py
the command I am using to run pytest:
python -m pytest ./src/test
and I am inside some_project folder and also using main_0.py instead of main.py because to not get confused with main folder
Edit 2:
I am to run the test case successfully by adding sys.path in the test_main_0.py file but it is breaking linting and hinting in the code editor (vscode) it didn't broke the linting and hinting, both import statement works but is there any better way.
new test_main_0.py:
import unittest
import os
import sys
sys.path.append(os.path.abspath("./src/main/lambda_function/some/"))
class TestSomeMain(unittest.TestCase):
def test_main_0(self):
from src.main.lambda_function.some.main_0 import lambda_handler # this works
from main_0 import lambda_handler # this also works but break linting and hinting in the code editor
res = lambda_handler()
assert res == "Hello"
could you please try
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
from some.s3 import PrintS3
def lambda_handler():
obj = PrintS3()
res = obj.print_txt()
return res
I found a somewhat working solution.
added setUp() and tearDown() methods in the class for inserting and removing path in sys.path
path in sys.path is the location of the directory where the main_0.py and s3.py is located
import unittest
import os
import sys
class TestSomeMain(unittest.TestCase):
def setUp(self) -> None:
sys.path.insert(0, os.path.abspath("./src/main/lambda_function/some/"))
def tearDown(self) -> None:
sys.path.remove(os.path.abspath("./src/main/lambda_function/some/"))
def test_main_0(self):
from src.main.lambda_function.some.main_0 import lambda_handler
res = lambda_handler()
assert res == "Hello"
also update the test command in the terminal:
python -m pytest ./src/test/unittest/lambda_function/some --cov ./src/main/lambda_function/some --cov-report html

How can I improve code coverage of Python3

With unittest and Coverage.py,
def add_one(num: int):
num = num + 1
return num
from unittest import TestCase
from add_one import add_one
class TestAddOne(TestCase):
def test_add_one(self):
self.assertEqual(add_one(0), 1)
self.assertNotEqual(add_one(0), 2)
and here is the coverage:
How can I test the whole file?
Assuming that your test file is called test_one.py run this command in the same directory:
coverage run -m unittest test_one.py && coverage report
Result should look similar to this:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Name Stmts Miss Cover
---------------------------------
add_one.py 3 0 100%
test_one.py 6 0 100%
---------------------------------
TOTAL 9 0 100%
You never call the test_add_one method.
Note how the function definition is executed, but not the body. To run your test, add a __main__ check and a TestSuite/TextTestRunner (https://docs.python.org/3/library/unittest.html)
from unittest import TestCase, TestSuite, TextTestRunner
from add_one import add_one
class TestAddOne(TestCase):
def test_add_one(self):
self.assertEqual(add_one(0), 1)
self.assertNotEqual(add_one(0), 2)
if __name__ == "__main__":
suite = TestSuite()
suite.addTest(TestAddOne("test_add_one"))
TextTestRunner().run(suite)
The result of
coverage run <file.py>
coverage html
# OR
coverage report -m
is all lines tested.

Function not defined when running tests in Python package

I am creating a Python package/library. My directory structure looks like this:
my_package/
|-- my_package/
| |-- tests/
| | |-- __init__.py
| | |-- my_tests.py
| |
| |-- __init__.py
| |-- main.py
|
|-- setup.py
I have all my functions in the main.py file:
def sum_nums(a,b):
res = a + b
return(res)
def mult_nums(a,b):
res = a * b
return(res)
def sub_nums(a,b):
res = a - b
return(res)
my_tests.py looks like this:
from unittest import TestCase
import my_package
def test_sum():
assert sum_nums(3,4) == 7
def test_mult():
assert mult_nums(3,4) == 12
def test_sub():
assert sub_nums(3,4) == -1
When I run my tests from the package root directory as follows:
python setup.py test
... I get the following error:
NameError: name 'sum_nums' is not defined
Is my package directory structure correct?
Am I missing an _ init _.py file?
Does every directory require an _ init _.py file?
Is it okay to place all my functions inside a single main.py file
without using if name == "main"?
You need to indicate that the functions under test came for the my_package package like:
from unittest import TestCase
import my_package
def test_sum():
assert my_package.sum_nums(3,4) == 7
def test_mult():
assert my_package.mult_nums(3,4) == 12
def test_sub():
assert my_package.sub_nums(3,4) == -1
tests should not be in the package so move it up one dir. See sanic or any other module in github for example. Your functions need to be available in init.py. You can import them like is done in sanic.
https://github.com/huge-success/sanic
You also need
from my_package import sum_nums, mult_nums, sub_nums
Or prefix with my_package.

Python unittest not recognizing tests

I'm trying to learn how to use the unittest framework in python. I keep getting the message below when I run my file containing the tests.
----------------------------------------------------------------------
Ran 0 tests in 0.000s
OK
I've searched here and elsewhere and can't figure out why it is not recognizing the tests. Each test starts with test and the other portions of the unittest seem to match what the documentation requires.
Here is the text of the script:
import unittest
from datetime import datetime, timedelta
class Activity(object):
'Holds detail information on a activity'
def __init__(self, location, activity_name, activity_id, start_date, end_date):
self.activity_name = activity_name
self.activity_id = activity_id
self.start_date = datetime.strptime(start_date, '%m/%d/%Y').date()
self.end_date = datetime.strptime(end_date, '%m/%d/%Y').date()
self.location = location
if __name__ == '__main__':
unittest.main()
class TestActivity(unittest.TestCase):
def setUp(self):
self.activity = Activity('UVU', 'OpenWest', 'Beginning Python'
, '00000', '12/1/2013', '12/30/3013')
def test_activity_creation(self):
self.assertEqual(self.activity.location, 'UVU')
self.assertEqual(self.activity.activity_name, 'OpenWest')
self.assertEqual(self.activity.activity_id, '00000')
self.assertEqual(self.activity.start_date, datetime.strptime('12/1/2013', '%m/%d/%Y').date())
self.assertEqual(self.activity.start_date, datetime.strptime('12/30/2013', '%m/%d/%Y').date())
def test1(self):
self.assertEqual(1,1)
def tearDown(self):
del self.activity
Any help is appreciated
If you move
if __name__ == '__main__':
unittest.main()
To the end of the script, then it will work.
Update
Here is my speculation: when you called unittest.main() in the middle of the script, your test class has not been defined yet, thus unittest did not pick up any tests. By moving the unittest.main() to the end, or more precisely--after your define your test class, you make sure that unittest sees those tests.
main() isn't needed.
Django is picky on where the tests are. If your app is in myapp/, tests should be in myapp/tests.py as I recall.
Example:
./manage.py test
or
./manage.py test -v2 myapp
Here was my solution using python3.9. The trick was to prefix the test file with test, all lower case. (I followed it with an underscore for visual separation, but it's not required.)
Directory structure:
Some-Project
└── server
   └── api-devops
└── scripts
       └── crash_monitoring
         ├── CrashDump.py
         ├── test_CrashDump.py
        ├── env
        └── requirements.txt
Contents of test_CrashDump.py:
import unittest
class CrashDumpTest(unittest.TestCase): # The class name is irrelevant. It does not need to contain the word 'test'.
def test_something(self): # Like the filename, the function name must begin with 'test'
self.assertTrue(True)
As #johntellsall says, main() isn't needed.
Command to run from root directory, Some-Project:
(env) Some-Project cameronhudson$ python3 -m unittest discover -s ./server/api-devops/scripts/crash_monitoring
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Command to run from the directory containing the tests, crash_monitoring:
(env) crash_monitoring cameronhudson$ python3 -m unittest
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK

Categories

Resources