Modellierung und Simulation - Modultest: Unterschied zwischen den Versionen
| Zeile 346: | Zeile 346: | ||
suite = testsuite('TestAddiere'); | suite = testsuite('TestAddiere'); | ||
results = run(suite); | results = run(suite); | ||
=== TestRunner mit Textausgabe === | |||
Das ist ein „professioneller Runner“, der einen strukturierten Bericht erzeugt. | |||
import matlab.unittest.TestRunner | |||
runner = TestRunner.withTextOutput; | |||
'''Test ausführen''' | |||
results = runner.run(suite); | |||
'''Beispielausgabe (detaillierter Bericht)''' | |||
Running TestAddiere | |||
TestAddiere/testPositive .... PASSED | |||
TestAddiere/testNegative .... PASSED | |||
TestAddiere/testMixed .... PASSED | |||
Done TestAddiere | |||
= Praktische Übung = | = Praktische Übung = | ||
Version vom 25. Juni 2026, 14:05 Uhr
| Autor: | Prof. Dr.-Ing. Schneider |
| Lektion: | 11 |
| Termin: | 26.06.2026 |
Einleitung
Modultests bilden die unterste Ebene des Testprozesses und dienen dazu, einzelne Softwareeinheiten frühzeitig und isoliert auf ihre korrekte Funktion zu überprüfen. Ziel ist es, Fehler bereits in einem sehr frühen Entwicklungsstadium zu erkennen, um spätere Integrationsprobleme zu vermeiden und die Gesamtqualität des Systems nachhaltig zu erhöhen. Dabei wird jedes Modul unabhängig von anderen Komponenten getestet, wobei sowohl funktionale Anforderungen als auch typische Fehlerszenarien betrachtet werden. Durch klar definierte Testfälle, reproduzierbare Testumgebungen und objektive Bewertungskriterien stellen Modultests sicher, dass die implementierten Funktionen robust, zuverlässig und spezifikationskonform sind.
Lernziele
Nach dieser Lektion können Sie
- die Bedeutung von Unit-Tests erklären,
- MATLAB-Testklassen erstellen,
- Tests mit dem matlab.unittest Framework durchführen,
- Test Fixtures verwenden,
- Fehlerfälle gezielt prüfen,
- Testberichte interpretieren,
- Unit-Tests in Entwicklungsprozesse integrieren.
Vorbereitung
- Studieren Sie das Video Erste Schritte mit dem MATLAB Unit Test Framework.
- Weitere Informationen finden Sie im Artikel Ways to Write Unit Tests.
- Besuchen Sie den Online-Kurs Unit Testing
- Lassen Sie sich vom Copilot helfen einen Test zu generieren.
1. Motivation
Bei wissenschaftlicher Software entstehen häufig Fehler durch:
- Änderungen am Algorithmus
- Erweiterungen bestehender Funktionen
- Refactoring
- Teamarbeit
Unit-Tests stellen sicher, dass eine Funktion auch nach Änderungen weiterhin korrekt arbeitet.
Beispiel
Gegeben sei die Funktion:
function y = celsius2fahrenheit(x)
y = x*9/5 + 32;
end
Frage: Wie kann sichergestellt werden, dass zukünftige Änderungen keine Fehler verursachen?
Antwort: → Automatisierte Unit-Tests.
2. Das MATLAB Unit-Test Framework
MATLAB stellt das Paket
matlab.unittest
bereit.
| Element | Zweck |
|---|---|
TestCase |
Basisklasse für Tests |
verifyEqual |
Ergebnis prüfen |
verifyTrue |
Wahrheitswert prüfen |
verifyError |
Fehler erwarten |
TestSuite |
Testsammlung |
TestRunner |
Testausführung |
3. Erster Test
Zu testende Funktion
function y = quadrat(x)
y = x.^2;
end
Testklasse
classdef TestQuadrat < matlab.unittest.TestCase
methods(Test)
function testPositive(testCase)
actual = quadrat(4);
expected = 16;
testCase.verifyEqual(actual,expected);
end
end
end
Test ausführen
results = runtests('TestQuadrat');
Ausgabe:
Running TestQuadrat . Done TestQuadrat
4. Mehrere Testfälle
classdef TestQuadrat < matlab.unittest.TestCase
methods(Test)
function testPositive(testCase)
actual = quadrat(4);
expected = 16;
testCase.verifyEqual(actual,expected);
end
end
end
5. Toleranzen bei Fließkommazahlen
Direkte Vergleiche sind problematisch:
0.1 + 0.2 == 0.3
Daher
actual = sin(pi);
testCase.verifyEqual( ...
actual,...
0,...
'AbsTol',1e-10);
6. Fehler testen
Funktion
function y = wurzel(x)
if x < 0
error('MATLAB:NegativeInput',...
'Nur positive Werte erlaubt')
end
y = sqrt(x);
end
Test
function testError(testCase)
testCase.verifyError( ...
@() wurzel(-5), ...
'MATLAB:NegativeInput');
end
7. Parameterisierte Tests
Oft möchte man dieselbe Funktion mit vielen verschiedenen Eingabewerten testen. Ohne parameterisierte Tests müsste man für jeden Fall eine eigene Testmethode schreiben.
| TestQuadrat ohne Parameterisierung |
classdef TestQuadrat < matlab.unittest.TestCase
methods(Test)
function test0(testCase)
testCase.verifyEqual(quadrat(0),0);
end
function test1(testCase)
testCase.verifyEqual(quadrat(1),1);
end
function test2(testCase)
testCase.verifyEqual(quadrat(2),4);
end
function test3(testCase)
testCase.verifyEqual(quadrat(3),9);
end
end
end
|
Das funktioniert, ist aber:
- viel Code
- schlecht wartbar
- fehleranfällig
Die elegantere Lösung besteht darin die Testdaten als Eigenschaften zu definieren:
classdef TestQuadrat < matlab.unittest.TestCase
properties(TestParameter)
x = {0,1,2,3};
y = {0,1,4,9};
end
methods(Test)
function testQuadrat(testCase,x,y)
testCase.verifyEqual(quadrat(x),y);
end
end
end
Testausführung
results = runtests('TestQuadrat');
Ausgabe:
Running TestQuadrat .... Done TestQuadrat
8. Testumgebung
Jeder Test soll unter definierten und reproduzierbaren Bedingungen starten.
Typische Vorbereitungen sind:
- Testdaten laden
- Dateien erzeugen
- Verzeichnisse anlegen
- Hardware initialisieren
- Parameter setzen
- Objekte erzeugen
Ohne Fixtures müsste derselbe Vorbereitungscode in jeder Testmethode wiederholt werden.
Beispiel
Angenommen mehrere Tests benötigen dieselbe Abtastrate
fs = 1000; % in Hz
In der Funktion setup wird die Abtastrate definiert.
methods(TestMethodSetup)
function setup(testCase)
testCase.TestData.fs = 1000;
end
end
Testmethode
classdef TestFilter < matlab.unittest.TestCase
methods(TestMethodSetup)
function setup(testCase)
testCase.TestData.fs = 1000;
end
end
methods(Test)
function testLength(testCase)
fs = testCase.TestData.fs;
end
function testAmplitude(testCase)
fs = testCase.TestData.fs;
end
end
end
Anwendung
fs = testCase.TestData.fs;
Typische Anwendungen:
- Messdaten laden
- Simulationsumgebungen vorbereiten
- Testverzeichnisse anlegen
9. Beispiel aus der Signalverarbeitung
Zu testende Funktion
function y = movingAverage(x)
y = movmean(x,3);
end
Test
classdef TestMovingAverage ...
< matlab.unittest.TestCase
methods(Test)
function testConstantSignal(testCase)
x = ones(1,100);
y = movingAverage(x);
testCase.verifyEqual(y,x,'AbsTol',1e-12);
end
end
end
10. Testbericht
Ein Testbericht ist die strukturierte Ausgabe aller Testergebnisse nach der Ausführung einer Testsuite. Er zeigt nicht nur, ob Tests bestanden wurden, sondern auch welche Tests, warum, wie lange und mit welchem Ergebnis.
In MATLAB erfolgt das über das Unit-Test-Framework MATLAB mit dem TestRunner.
Wenn Sie Tests ausführst, willen Sie typischerweise mehr als nur:
OK / FAILED
Ein Testbericht beantwortet z. B.:
- Welche Tests wurden ausgeführt?
- Welche sind bestanden/fehlgeschlagen?
- Welche Fehler sind aufgetreten?
- Wie lange hat jeder Test gedauert?
- Gab es Warnungen oder Abbrüche?
Standard-Testausführung
suite = testsuite(pwd); results = runtests(suite);
Tipp: pwd ist eine eingebaute MATLAB-Funktion und steht für Print Working Directory. pwd gibt den aktuellen Arbeitsordner zurück, also den Ordner, in dem MATLAB gerade arbeitet.
TestRunner für detaillierte Berichte
Der zentrale Baustein ist der TestRunner
runner = matlab.unittest.TestRunner.withTextOutput; results = runner.run(suite);
TestRunnerführt die Tests kontrolliert auswithTextOutputerzeugt eine strukturierte Textausgaberesultsenthält alle Testergebnisse als Objektliste
Auswertung:
- Passed
- Failed
- Incomplete
- Duration
Beispiel
Zu testende Funktion
function y = addiere(a,b) y = a + b; end
Testklasse
classdef TestAddiere < matlab.unittest.TestCase
methods(Test)
function testPositive(testCase)
testCase.verifyEqual(addiere(2,3),5);
end
function testNegative(testCase)
testCase.verifyEqual(addiere(-2,-3),-5);
end
function testMixed(testCase)
testCase.verifyEqual(addiere(-2,5),3);
end
end
end
Standard-Testausführung
results = runtests('TestAddiere');
Typische Ausgabe im Command Window
Running TestAddiere ... Done TestAddiere
- Jeder Punkt . = Test bestanden
- F = Failed
- E = Error
Ausgabe als Ergebnisobjekte
results =
1×3 TestResult array
Name Passed Failed Incomplete Duration ____________________ ______ ______ __________ ________ TestAddiere/testPositive true false false 0.0012 TestAddiere/testNegative true false false 0.0009 TestAddiere/testMixed true false false 0.0010
äquivalente Alternative
suite = testsuite('TestAddiere');
results = run(suite);
TestRunner mit Textausgabe
Das ist ein „professioneller Runner“, der einen strukturierten Bericht erzeugt.
import matlab.unittest.TestRunner runner = TestRunner.withTextOutput;
Test ausführen
results = runner.run(suite);
Beispielausgabe (detaillierter Bericht)
Running TestAddiere
TestAddiere/testPositive .... PASSED TestAddiere/testNegative .... PASSED TestAddiere/testMixed .... PASSED
Done TestAddiere
Praktische Übung
Aufgabe 11.1
Implementieren Sie:
function y = cube(x)
Erstellen Sie mindestens drei Unit-Tests.
| Musterlösung 11.1 |
classdef TestMovingAverage ...
< matlab.unittest.TestCase
methods(Test)
function testConstantSignal(testCase)
x = ones(1,100);
y = movingAverage(x);
testCase.verifyEqual( ...
y,...
x,...
'AbsTol',1e-12);
end
end
end
|
Aufgabe 2
Entwickeln Sie Tests für:
function y = celsius2fahrenheit(x)
Prüfen Sie:
- 0 °C
- 100 °C
- −40 °C
| Musterlösung 11.1 |
classdef TestMovingAverage ...
< matlab.unittest.TestCase
methods(Test)
function testConstantSignal(testCase)
x = ones(1,100);
y = movingAverage(x);
testCase.verifyEqual( ...
y,...
x,...
'AbsTol',1e-12);
end
end
end
|
Aufgabe 3
| Musterlösung 11.1 |
classdef TestMovingAverage ...
< matlab.unittest.TestCase
methods(Test)
function testConstantSignal(testCase)
x = ones(1,100);
y = movingAverage(x);
testCase.verifyEqual( ...
y,...
x,...
'AbsTol',1e-12);
end
end
end
|
Aufgabe 4
| Musterlösung 11.1 |
classdef TestMovingAverage ...
< matlab.unittest.TestCase
methods(Test)
function testConstantSignal(testCase)
x = ones(1,100);
y = movingAverage(x);
testCase.verifyEqual( ...
y,...
x,...
'AbsTol',1e-12);
end
end
end
|
→ MATLAB® Befehlsübersicht
→ zurück zum Hauptartikel: BSE Modellierung und Simulation - SoSe26