Evaluatoren
Jeder Evaluator kann eine Menge von Auswertungsschritten (Capabilities) unterstützen. Diese sind
derzeit: compile
, test
, style
.
Eigene Evaluatoren mit Python implementieren
Für einen neuen Evaluator ist eine Subklasse von eva.pltform.evaluation.core.eval.Evaluator
anzulegen und die Setup-Methode zu überschreiben:
class JavaEvaluator(Evaluator):
# ...
def setup(self, ctx: EvaluationContext):
# Evaluator-spezifische Validierungslogik: Bestimmte Anfragen zurückweisen
check_dynamic_asserts(ctx)
# Eigene Parameter verarbeiten
java_args, javac_args = configure_jvm(ctx)
# Handler definieren, die bei jedem Auswertungsschritt aufgerufen werden sollen:
return ExecutionHandlerConfig(
compile=JavaCompileHandler(javac_args=javac_args),
style=JavaStyleHandler(java_args=java_args),
test=JavaTestHandler(java_args=java_args),
coverage=JavaCoverageHandler(javac_args=javac_args, java_args=java_args)
)
In den Handlern kann dann die Auswertungslogik implementiert werden:
class JavaTestHandler(TestHandler):
def __init__(self, java_args):
self.java_args = java_args
def run(self, evaluator: Evaluator, ctx: EvaluationContext) -> TestResult:
test_fqcns = [to_fqcn(f) for f in ctx.payload.test_files]
r = ctx.env.bash(
[
f'java {self.java_args} -cp $EJUNIT_RUNNER_PATH:$CLASSPATH:classes',
'de.hsrm.sls.ejunit.mono.Runner -o trex_report.xml',
f'-s {ctx.opts.max_output_size}',
*test_fqcns,
],
max_output_size=ctx.opts.max_output_size,
timeout=ctx.opts.test_timeout,
)
r.expect(status=[CODE_SUCCESS, CODE_TIMEOUT])
testsuite = self.trex.parse(ctx.env.read_file('trex_report.xml')).fix_timeouts(
ctx.opts.test_timeout
)
return self.mapper.map(testsuite=testsuite, output=r.out())
ctx.env
bietet die Schnittstelle für den Zugriff auf die Umgebung. Darüber können Befehle
ausgeführt, Verzeichnisse angelegt oder Dateien gelesen werden. Zudem gibt es Asserts (z.B.
r.expect
), die sicherstellen, dass der Befehl korrekt ausgeführt wurde. Mit ctx.payload
kann auf
die Anfrage zugegriffen werden und ctx.opts
ermöglicht den Zugriff auf die Konfiguration.
Anschließend müssen Metadaten in der Klasse ergänzt werden:
class JavaEvaluator(Evaluator):
id = 'java'
supported_envs = 'java*'
default_env = 'java19'
capability = EvaluatorCapability(compile=True, style=True, test=True)
id
: Eindeutige IDsupported_envs
: Unix glob-Pattern, welches alle Umgebungen matcht, für die der Evaluator verwendet werden kanndefault_env
: Der Selektor für den Evaluation Stack bietet die Möglichkeit, die Umgebung wegzulassen. In dem Fall wird die angegebene Umgebung als Default verwendetcapability
: Auswertungsschritte, die der Evaluator unterstützt
Damit der Evaluator zur Verfügung steht, muss die Implementierung in der EvaluatorRegistry
konfiguriert werden:
class EvaluatorRegistry:
# ...
def _load_evaluators(self):
if self._evaluators is None:
self._evaluators = [
# ...
JavaEvaluator,
]
return self._evaluators
Integration-Tests für eigenen Evaluator schreiben
Evaluatoren lassen sich sehr einfach über Integration-Tests debuggen. Gleichzeitig stellt man die Qualität sicher und sorgt dafür, dass der Evaluator automatisch getestet werden kann. Hierfür sind ein (oder mehrere) Testmodule anzulegen:
@pytest.mark.evaluator('java') # 'java' ist die zuvor vergebene ID des Evaluators
class JavaTest:
def test_passing(self, ctx: TestContext):
payload = EvalPayload(
solution_files=[
EvaFile(path='Heron.java', content=ctx.fixtures.load('java/passing/Heron.java'))
],
test_files=[
EvaFile(
path='HeronTest.java', content=ctx.fixtures.load('java/passing/HeronTest.java')
)
],
include_files=[],
compile=True,
test=True,
)
result = ctx.eval(payload)
assert result.compilation.compiling
assert pytest.approx(result.test.correctness) == 1.0
# ...
Unter eva.pltform/tests/integration/fixtures
können die Dateien organisiert werden, die für die
einzelnen Testfälle benötigt werden. Der Pfad in ctx.fixtures.load
ist relativ zu diesem
Verzeichnis.
Zuletzt muss der Evaluator noch mit den Umgebungen für die Tests registriert werden:
env_map = {
# ...
'java': ['java19', 'java20', 'java21'],
}
Der Eintrag definiert alle Umgebungen (java19
, java20
, java21
), die für Tests mit dem
Evaluator java
verwendet werden sollen. Alle Testfälle in Klassen, die mit
@pytest.mark.evaluator('java')
annotiert werden, werden einmal für jede dieser Umgebungen
ausgeführt. Weitere Infos zur Ausführung der Tests finden sich unter
Integration-Tests.