Skip to content

Testing

bondlegend4 edited this page Sep 16, 2024 · 1 revision

To use pytest with the proposed directory structure, you'll follow a few key practices to ensure pytest can discover and execute your tests, even with different levels of nesting and organization. Here's how you can set it up:

1. Install pytest (if you haven't already)

Make sure you have pytest installed in your virtual environment:

pip install pytest

2. Naming conventions

pytest automatically discovers test files and functions based on their names. For smooth integration with your directory structure:

  • Test files should be named with the prefix test_ or suffix _test. For example, test_openplc.py or openplc_test.py.
  • Test functions should also follow the same naming convention, starting with test_, e.g., def test_modbus_communication():.

3. Add __init__.py if needed

For pytest to recognize directories as Python packages, you might need to add an empty __init__.py file in directories containing Python test code.

For example:

tests/
├── __init__.py        # Marks tests directory as a Python package
├── openplc/
│   ├── python/
│   │   ├── __init__.py    # Marks python directory as a package
│   │   ├── test_openplc.py  # Contains your pytest tests

This ensures pytest recognizes your structure, but depending on the Python version, it may not be strictly necessary anymore.

4. Run pytest in your project root

To execute all tests, navigate to your project’s root directory (where docker_compose.yml, Makefile, and README.md are located) and simply run:

pytest

This will:

  • Automatically find all test_*.py or *_test.py files.
  • Collect test functions from those files and execute them.

pytest will recursively look for tests in subdirectories like tests/openplc/python/ and tests/scada_lts/python/.

5. Organize tests with pytest fixtures

If you have common setup code (e.g., starting up a container or initializing a simulation), you can define it as a fixture in a conftest.py file, which pytest automatically discovers.

For example, in tests/conftest.py:

import pytest

@pytest.fixture(scope="module")
def modbus_connection():
    # Set up your Modbus connection or mock here
    connection = setup_modbus_connection()
    yield connection
    # Teardown the connection after the test is done
    connection.close()

Then in your tests (e.g., tests/openplc/python/test_openplc.py):

def test_modbus_read(modbus_connection):
    result = modbus_connection.read_holding_registers(1, 10)
    assert result == expected_value

6. Non-Python Tests

For tests that aren't Python-based (like PLC programs or SCADA configuration tests), you can still organize them under tests/openplc/non-python/ or tests/scada_lts/non-python/. While pytest won't execute these files directly, you can create Python test scripts that:

  • Call external command-line tools to run these tests.
  • Validate the expected results (e.g., checking that the PLC program loads successfully).

For example, in tests/openplc/non-python/test_plc_load.py:

import subprocess

def test_plc_program_load():
    # Example of calling an external tool or script
    result = subprocess.run(['openplc_runtime', '--load', 'path_to_plc_program.st'], capture_output=True, text=True)
    assert "Load successful" in result.stdout

7. Running specific tests

You can run specific test directories or files with pytest. For example:

  • Run only OpenPLC tests:
    pytest tests/openplc
  • Run a specific test file:
    pytest tests/scada_lts/python/test_scada.py

Final Structure:

├── docker_compose.yml     
├── LICENSE                
├── Makefile               
├── openplc/               
│   └── src/               
│   └── files/             
├── scada_lts/             
│   └── hmi/               
├── simulations/           
│   └── irrigation_simulator.py
│   └── main.py
│   └── modbus_io.py
├── tests/                 
│   ├── conftest.py        # Shared pytest fixtures
│   ├── openplc/           
│   │   ├── python/        
│   │   │   └── test_openplc.py  
│   │   └── non-python/    
│   │       └── test_plc_load.py
│   ├── scada_lts/         
│   │   ├── python/        
│   │   └── non-python/    
│   ├── simulations/       
│   │   └── python/        
│   ├── integration/       
│   │   └── python/        
│   │   └── non-python/    
├── README.md              

This setup keeps everything clean and manageable while ensuring pytest can handle both Python and non-Python aspects of your project. Let me know if you need more details on a specific part!