How to test PZero - gecos-lab/PZero GitHub Wiki
Pytest is a framework for testing Python code, it requires Python 3.7+ or PyPy3.
If you have already installed on your OS pytest
and activated Pzero's conda environment you can skip the Installation step, go here to the Testing step!
If you want to create tests and you have already installed pytest, go here:
-
Based on your environment/package manager install pytest inside your terminal:
conda/pip install pytest
-
Check if pytest is installed:
pytest --version -> pytest 7.3.1
-
Go inside PZero's folder (not pzero lowercase) from the terminal:
cd C:\_path_to_PZero_folder
-
Run pytest for testing all the tests inside PZero's folder (this can be applied to every folder containing a set of tests):
pytest
-
Running a single test:
-
go inside "tests" folder:
cd tests
-
run the specific test (instead of test_example.py insert your test's name file):
pytest -q test_example.py
-
-
Optional commands:
-
running pytest and get the test coverage:
pytest --cov
-
running pytest and get all the fixtures for each test:
pytest --fixtures
-
if you want to see how to run pytest in other ways see the official docs
-
-
All the test files names need to start with the word 'test', for example some of the tests inside the folder 'test_collections' are:
test_background_collection.py test_boundary_collection.py test_dom_collection.py ...
-
All the tests structure need to reflect the structure of the project architecture. For example, we have a 'collections' folder in 'pzero' and that needs to be reflected inside the 'tests' folder with a 'test_collections' folder :
collections test_collections
background_collection.py test_background_collection.py
boundary_collection.py <------> test_boundary_collection.py
dom_collection.py test_dom_collection.py
... ...
-
Like testing files, the testing methods and classes need to start with the word 'test' because pytest runs all the files, classes and methods starting with 'test':
class TestBoundaryCollection: def test_add_entity_from_dict(self): # this function will be called by pytest assert ... def example_function(self): # this function will never be called by pytest (unless it's called by test_add_entity_from_dict() or another testing method) return ...
-
Like testing files, the testing methods and classes need to start with the word 'test' because pytest runs all the files, classes and methods starting with 'test':
class TestBoundaryCollection: def test_add_entity_from_dict(self): # this function will be called by pytest assert ... def example_function(self): # this function will never be called by pytest (unless it's called by test_add_entity_from_dict() or another testing method) return ...
-
You can use the assert statement to verify test expectations, in the following test example we add an entity inside a dictionary, then we check if the number of entities is one and if the entity uid inserted is in the uids of the collection. The assert keyword lets you test if a condition in your code returns True, if not, the program will raise an AssertionError:
def test_add_entity_from_dict(self): # add an entity inside the collection dictionary collection.add_entity_from_dict(entity) # check if the entities number is equal to the add_entity calls assert collection.get_number_of_entities() == 1 # check if the uid inserted is in the uids of the collection assert entity['uid'] in collection.get_uids()
-
When you need to test a method or a class using PyQt you need to:
- import pytest at the beginning of the test file:
import pytest
- add the fixture annotation before a method and qtbot inside that method:
@pytest.fixture def test_shown_table(self, qtbot):
- sometimes on your local machine the tests don't run if we have the fixture annotation for qtbot, in that case, you can comment it but remember to uncomment it before pushing it to GitHub, because the annotation it's needed when running GitHub Actions:
# @pytest.fixture def test_shown_table(self, qtbot):
- import pytest at the beginning of the test file:
-
If you need to skip a test you can use this annotation:
@pytest.mark.skip(reason="ViewMap has no attribute 'entity_remove_selected") def test_initialize_menu_tools(self, qtbot):