--- a/src/eric7/Testing/Interfaces/TestExecutorBase.py Tue Dec 12 16:43:51 2023 +0100 +++ b/src/eric7/Testing/Interfaces/TestExecutorBase.py Wed Dec 13 15:54:55 2023 +0100 @@ -10,7 +10,7 @@ import os -from dataclasses import dataclass +from dataclasses import dataclass, field from enum import IntEnum from PyQt6.QtCore import QObject, QProcess, QProcessEnvironment, pyqtSignal @@ -56,27 +56,29 @@ """ interpreter: str # path of the Python interpreter - discover: bool # auto discovery flag - discoveryStart: str # start directory for auto discovery - testFilename: str # name of the test script - testName: str # name of the test function - testMarkerExpression: str # marker expression for test selection - testNamePattern: str # test name pattern expression or list - failFast: bool # stop on first fail - failedOnly: bool # run failed tests only - collectCoverage: bool # coverage collection flag - eraseCoverage: bool # erase coverage data first - coverageFile: str # name of the coverage data file + discover: bool = False # auto discovery flag + discoveryStart: str = "" # start directory for auto discovery + testCases: list = field(default_factory=list) # list of selected test cases + testFilename: str = "" # name of the test script + testName: str = "" # name of the test function + testMarkerExpression: str = "" # marker expression for test selection + testNamePattern: str = "" # test name pattern expression or list + failFast: bool = False # stop on first fail + failedOnly: bool = False # run failed tests only + collectCoverage: bool = False # coverage collection flag + eraseCoverage: bool = False # erase coverage data first + coverageFile: str = "" # name of the coverage data file + discoverOnly: bool = False # test discovery only class TestExecutorBase(QObject): """ Base class for test framework specific implementations. - @signal collected(list of tuple of (str, str, str, str, int)) emitted after all - tests have been collected. Tuple elements are the test id, the test name, - a short description of the test, the test file name and the line number of - the test. + @signal collected(list of tuple of (str, str, str, str, int, list)) emitted after + all tests have been collected. Tuple elements are the test id, the test name, + a short description of the test, the test file name, the line number of + the test and the elements of the test path as a list. @signal collectError(list of tuple of (str, str)) emitted when errors are encountered during test collection. Tuple elements are the test name and the error message. @@ -89,10 +91,14 @@ @signal testRunAboutToBeStarted() emitted just before the test run will be started. @signal testRunFinished(int, float) emitted when the test run has finished. - The elements are the number of tests run and the duration in seconds + The elements are the number of tests run and the duration in seconds. @signal stop() emitted when the test process is being stopped. @signal coverageDataSaved(str) emitted after the coverage data was saved. The element is the absolute path of the coverage data file. + @signal discoveryAboutToBeStarted() emitted just before the test discovery + will be started + @signal discoveryFinished(int, float) emitted when the discovery has finished. + The elements are the number of discovered tests and the duration in seconds. """ collected = pyqtSignal(list) @@ -104,6 +110,8 @@ testRunFinished = pyqtSignal(int, float) stop = pyqtSignal() coverageDataSaved = pyqtSignal(str) + discoveryAboutToBeStarted = pyqtSignal() + discoveryFinished = pyqtSignal(int, float) module = "" name = "" @@ -245,6 +253,29 @@ return process + def discover(self, config, pythonpath): + """ + Public method to start the test discovery process. + + @param config configuration for the test discovery + @type TestConfig + @param pythonpath list of directories to be added to the Python path + @type list of str + @exception RuntimeError raised if the the test discovery process did not start + @exception ValueError raised if no start directory for the test discovery was + given + """ + if not config.discoveryStart: + raise ValueError("No discovery start directory given.") + + self.__process = self._prepareProcess(config.discoveryStart, pythonpath) + discoveryArgs = self.createArguments(config) + self.discoveryAboutToBeStarted.emit() + self.__process.start(config.interpreter, discoveryArgs) + running = self.__process.waitForStarted() + if not running: + raise RuntimeError("Test discovery process did not start.") + def start(self, config, pythonpath): """ Public method to start the testing process.