Modellierung und Simulation - Modultest: Unterschied zwischen den Versionen
| (30 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 99: | Zeile 99: | ||
<syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef TestQuadrat < matlab.unittest.TestCase | <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef TestQuadrat < matlab.unittest.TestCase | ||
methods(Test) | methods(Test) | ||
function | function testPositiv(testCase) | ||
testCase.verifyEqual(quadrat(3),9); | |||
end | |||
function testNegativ(testCase) | |||
testCase.verifyEqual( | testCase.verifyEqual(quadrat(-4),16); | ||
end | |||
function testNull(testCase) | |||
testCase.verifyEqual(quadrat(0),0); | |||
end | end | ||
end | end | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Test ausführen == | |||
results = runtests('TestQuadrat'); | |||
'''Ausgabe:''' | |||
Running TestQuadrat | |||
. | |||
Done TestQuadrat | |||
=5. Toleranzen bei Fließkommazahlen= | =5. Toleranzen bei Fließkommazahlen= | ||
Direkte Vergleiche sind problematisch: | Direkte Vergleiche sind problematisch: | ||
| Zeile 113: | Zeile 124: | ||
Daher | Daher | ||
<syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">actual = sin(pi); | <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">actual = sin(pi); | ||
testCase.verifyEqual( | testCase.verifyEqual(actual, 0, 'AbsTol',1e-10); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Zeile 123: | Zeile 131: | ||
<syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">function y = wurzel(x) | <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">function y = wurzel(x) | ||
if x < 0 | if x < 0 | ||
error('MATLAB:NegativeInput', | error('MATLAB:NegativeInput','Nur positive Werte erlaubt') | ||
end | end | ||
y = sqrt(x); | y = sqrt(x); | ||
| Zeile 132: | Zeile 139: | ||
== Test == | == Test == | ||
<syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">function testError(testCase) | <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">function testError(testCase) | ||
testCase.verifyError( ... | testCase.verifyError( ... | ||
@() wurzel(-5), ... | @() wurzel(-5), ... | ||
'MATLAB:NegativeInput'); | 'MATLAB:NegativeInput'); | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Zeile 147: | Zeile 152: | ||
| <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef TestQuadrat < matlab.unittest.TestCase | | <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef TestQuadrat < matlab.unittest.TestCase | ||
methods(Test) | methods(Test) | ||
function test0(testCase) | function test0(testCase) | ||
| Zeile 181: | Zeile 186: | ||
end | end | ||
methods(Test) | methods(Test,ParameterCombination = "sequential") % Parameter werden sequentiell verglichen 0-0, 1-1, 2-4, 3-9 | ||
function testQuadrat(testCase,x,y) | function testQuadrat(testCase,x,y) | ||
testCase.verifyEqual(quadrat(x),y); | testCase.verifyEqual(quadrat(x),y); | ||
| Zeile 197: | Zeile 202: | ||
= 8. Testumgebung = | = 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 == | == Beispiel == | ||
Angenommen mehrere Tests benötigen dieselbe Abtastrate | |||
fs = 1000; % in Hz | |||
In der Funktion <code>setup</code> wird die Abtastrate definiert. | |||
<syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">methods(TestMethodSetup) | <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">methods(TestMethodSetup) | ||
| Zeile 207: | Zeile 225: | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Testmethode == | |||
<syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">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 | |||
</syntaxhighlight> | |||
== Anwendung == | == Anwendung == | ||
fs = testCase.TestData.fs; | fs = testCase.TestData.fs; | ||
| Zeile 215: | Zeile 254: | ||
= 9. Beispiel aus der Signalverarbeitung = | = 9. Beispiel aus der Signalverarbeitung = | ||
Zu | Zu testende Funktion | ||
<syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">function y = movingAverage(x) | <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">function y = movingAverage(x) | ||
y = movmean(x,3); | y = movmean(x,3); | ||
| Zeile 227: | Zeile 266: | ||
x = ones(1,100); | x = ones(1,100); | ||
y = movingAverage(x); | y = movingAverage(x); | ||
testCase.verifyEqual( | testCase.verifyEqual(y,x,'AbsTol',1e-12); | ||
end | end | ||
end | end | ||
| Zeile 237: | Zeile 273: | ||
= 10. Testbericht = | = 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); | suite = testsuite(pwd); | ||
results = runtests(suite); | |||
Tipp: <code>pwd</code> ist eine eingebaute MATLAB-Funktion und steht für <code>Print Working Directory</code>. <code>pwd</code> 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; | runner = matlab.unittest.TestRunner.withTextOutput; | ||
results = runner.run(suite); | results = runner.run(suite); | ||
* <code>TestRunner</code> führt die Tests kontrolliert aus | |||
* <code>withTextOutput</code> erzeugt eine strukturierte Textausgabe | |||
* <code>results</code> enthält alle Testergebnisse als Objektliste | |||
Auswertung: | Auswertung: | ||
| Zeile 246: | Zeile 306: | ||
* Incomplete | * Incomplete | ||
* Duration | * Duration | ||
== Beispiel == | |||
Zu testende Funktion | |||
function y = addiere(a,b) | |||
y = a + b; | |||
end | |||
=== Testklasse === | |||
<syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">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 | |||
</syntaxhighlight> | |||
=== 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 with properties: | |||
Name | |||
Passed | |||
Failed | |||
Incomplete | |||
Duration | |||
Details | |||
Totals: | |||
3 Passed, 0 Failed, 0 Incomplete. | |||
0.038418 seconds testing time. | |||
=== ä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 = matlab.unittest.TestRunner.withTextOutput('Verbosity', matlab.unittest.Verbosity.Detailed); | |||
'''Test ausführen''' | |||
results = runner.run(suite) | |||
'''Beispielausgabe (detaillierter Bericht)''' | |||
Running TestAddiere | |||
Setting up TestAddiere | |||
Done setting up TestAddiere in 0 seconds | |||
Running TestAddiere/testPositive | |||
Done TestAddiere/testPositive in 0.0023986 seconds | |||
Running TestAddiere/testNegative | |||
Done TestAddiere/testNegative in 0.0016029 seconds | |||
Running TestAddiere/testMixed | |||
Done TestAddiere/testMixed in 0.0016074 seconds | |||
Tearing down TestAddiere | |||
Done tearing down TestAddiere in 0 seconds | |||
Done TestAddiere in 0.0056089 seconds | |||
== Test-Suite sichern und laden == | |||
Test-Suite sichern | |||
suite = testsuite(pwd); | |||
save suite.mat suite | |||
Test-Suite laden | |||
load suite.mat | |||
results = run(suite); | |||
== Test Browser == | |||
[[Datei:MATLABTestBrowser.png|thumb|rigth|300px|Abb. 1: MATLAB Test Browser]] | |||
Der MATLAB Test Browser ist eine grafische Oberfläche des MATLAB Unit Test Frameworks, mit der sich automatisierte Tests komfortabel verwalten und ausführen lassen. Er bietet einen schnellen Überblick über vorhandene Testdateien, Testklassen und Testmethoden und ermöglicht die gezielte Auswahl einzelner oder mehrerer Tests. Die Ergebnisse werden übersichtlich dargestellt, sodass erfolgreiche, fehlgeschlagene oder übersprungene Tests leicht erkannt und analysiert werden können. Dadurch unterstützt der Test Browser Entwickler dabei, die Qualität und Zuverlässigkeit von MATLAB-Code sicherzustellen und Fehler frühzeitig zu erkennen, ohne Tests ausschließlich über die Kommandozeile ausführen zu müssen. | |||
Sie finden ihn im Panel ab R2025a in dem auch der Copilot Chat zu finden ist. | |||
= Praktische Übung = | = Praktische Übung = | ||
| Zeile 255: | Zeile 399: | ||
Erstellen Sie mindestens drei Unit-Tests. | Erstellen Sie mindestens drei Unit-Tests. | ||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | {| role="presentation" class="wikitable mw-collapsible mw-collapsed" | ||
| <strong> | | <strong>Testklasse TestCube.m </strong> | ||
|- | |- | ||
| <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef | | <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef TestCube ... | ||
< matlab.unittest.TestCase | < matlab.unittest.TestCase | ||
methods(Test) | methods(Test) | ||
function testConstantSignal(testCase) | function testConstantSignal(testCase) | ||
x = -5:5; | |||
x = | y = cube(x); | ||
testCase.verifyEqual(y,x^3); | |||
y = | |||
testCase.verifyEqual( | |||
end | end | ||
end | end | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
|} | |} | ||
== Aufgabe 2 == | == Aufgabe 11.2 == | ||
Entwickeln Sie Tests für: | Entwickeln Sie Tests für: | ||
function y = celsius2fahrenheit(x) | function y = celsius2fahrenheit(x) | ||
| Zeile 288: | Zeile 421: | ||
* 100 °C | * 100 °C | ||
* −40 °C | * −40 °C | ||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | {| role="presentation" class="wikitable mw-collapsible mw-collapsed" | ||
| <strong> | | <strong>celsius2fahrenheit.m </strong> | ||
|- | |||
| <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">function F = celsius2fahrenheit(C) | |||
F = C*9/5 + 32; | |||
end | |||
</syntaxhighlight> | |||
|} | |||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | |||
| <strong>Testklasse TestCelsius2Fahrenheit.m </strong> | |||
|- | |- | ||
| <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef | | <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef TestCelsius2Fahrenheit < matlab.unittest.TestCase | ||
properties(TestParameter) | |||
C = {-40,0,100}; | |||
F = {-40,32,212}; | |||
end | |||
methods(Test) | methods(Test) | ||
function testConversion(testCase,C,F) | |||
testCase.verifyEqual( ... | |||
celsius2fahrenheit(C), ... | |||
F); | |||
end | |||
end | |||
end | |||
</syntaxhighlight> | |||
|} | |||
== Aufgabe 11.3 – Butterworth-Tiefpassfilter== | |||
Ein Butterworth-Tiefpassfilter 2. Ordnung soll getestet werden. | |||
Entwickeln Sie einen Test, der nachweist: | |||
* Ein konstantes Signal bleibt konstant. | |||
* Die Ausgangslänge entspricht der Eingangslänge. | |||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | |||
| <strong>TiefpassFilter.m </strong> | |||
|- | |||
| <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">function y = TiefpassFilter(x) | |||
fs = 100; | |||
fc = 5; | |||
n = 2; | |||
[b,a] = butter(n,fc/(fs/2)); | |||
y = filter(b,a,x); | |||
end | |||
</syntaxhighlight> | |||
|} | |||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | |||
| <strong>Testklasse TestTiefpassFilter  </strong> | |||
|- | |||
| <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef TestTiefpassFilter < matlab.unittest.TestCase | |||
methods(Test) | |||
function testLength(testCase) | |||
x = rand(1,1000); | |||
y = lowpassFilter(x); | |||
testCase.verifyEqual( ... | testCase.verifyEqual( ... | ||
y,... | length(y), ... | ||
x | length(x)); | ||
end | |||
function testConstantSignal(testCase) | |||
x = ones(1,1000); | |||
y = lowpassFilter(x); | |||
testCase.verifyEqual(y(end),1,'AbsTol',1e-2); | |||
end | end | ||
end | end | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
|} | |} | ||
== Aufgabe | == Aufgabe 11.4 – Testklasse entwickeln== | ||
Gegeben: | |||
<syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">function y = addiere(a,b) | |||
y = a+b; | |||
end | |||
</syntaxhighlight> | |||
Erstellen Sie eine vollständige Testklasse mit mindestens vier Testfällen. | |||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | {| role="presentation" class="wikitable mw-collapsible mw-collapsed" | ||
| <strong> | | <strong>Testklasse TestAddierer.m </strong> | ||
|- | |- | ||
| <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef | | <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef TestAddiere < matlab.unittest.TestCase | ||
methods(Test) | methods(Test) | ||
function testPositive(testCase) | |||
testCase.verifyEqual(addiere(3,4), 7); | |||
end | |||
function | function testNegative(testCase) | ||
testCase.verifyEqual(addiere(-2,-3), -5); | |||
end | |||
function testZero(testCase) | |||
testCase.verifyEqual(addiere(0,0), 0); | |||
end | |||
function testMixed(testCase) | |||
testCase.verifyEqual(addiere(-2,5),3); | |||
end | |||
end | |||
end | |||
</syntaxhighlight> | |||
|} | |||
== Aufgabe 11.5 – Fehlerbehandlung testen== | |||
Für die Funktion | |||
function y = wurzel(x) | |||
soll ein Fehler bei negativen Werten ausgelöst werden. | |||
#Implementieren Sie die Funktion. | |||
#Schreiben Sie den entsprechenden Unit-Test. | |||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | |||
| <strong>Funktion wurzel.m </strong> | |||
|- | |||
| <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">function y = wurzel(x) | |||
if x < 0 | |||
error('MATLAB:NegativeInput', ... | |||
'Nur positive Werte erlaubt'); | |||
end | end | ||
y = sqrt(x); | |||
end | |||
</syntaxhighlight> | |||
|} | |||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | |||
| <strong>Testklasse TestWurzel.m </strong> | |||
|- | |||
| <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef TestWurzel < matlab.unittest.TestCase | |||
methods(Test) | |||
function testPositive(testCase) | |||
testCase.verifyEqual(wurzel(9),3); | |||
end | |||
function testError(testCase) | |||
testCase.verifyError( ... | |||
@() wurzel(-5), ... | |||
'MATLAB:NegativeInput'); | |||
end | |||
end | |||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
|} | |} | ||
== Aufgabe | == Aufgabe 11.6 – Signalverarbeitung== | ||
Eine Filterfunktion soll getestet werden. | |||
Prüfen Sie: | |||
*Ausgangslänge | |||
*Konstantes Eingangssignal | |||
*Keine NaN-Werte im Ergebnis | |||
Implementieren Sie die Tests mit <code>verifyEqual</code>, <code>verifyTrue</code> und <code>verifyFalse</code>. | |||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | {| role="presentation" class="wikitable mw-collapsible mw-collapsed" | ||
| <strong> | | <strong>Funktion Butterworth.m </strong> | ||
|- | |- | ||
| <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small"> | | <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">function y = Butterworth(x) | ||
[b,a] = butter(2,0.1); | |||
y = filter(b,a,x); | |||
end | |||
</syntaxhighlight> | |||
|} | |||
{| role="presentation" class="wikitable mw-collapsible mw-collapsed" | |||
| <strong>Testklasse TestButterworth.m </strong> | |||
|- | |||
| <syntaxhighlight lang="matlab" line style="border: none; background-color: #EFF1C1; font-size:small">classdef TestButterworth < matlab.unittest.TestCase | |||
methods(Test) | methods(Test) | ||
function testOutputLength(testCase) | |||
x = rand(1,1000); | |||
y = myFilter(x); | |||
testCase.verifyEqual(length(y),length(x)); | |||
end | |||
function testConstantSignal(testCase) | function testConstantSignal(testCase) | ||
x = ones(1,1000); | |||
y = myFilter(x); | |||
testCase.verifyEqual(y(end),1,'AbsTol',1e-2); | |||
end | |||
x = | function testNoNaN(testCase) | ||
x = rand(1,1000); | |||
y = | y = Butterworth(x); | ||
testCase.verifyFalse(any(isnan(y))); | |||
testCase. | |||
end | end | ||
end | end | ||
end | end | ||
</syntaxhighlight> | </syntaxhighlight> | ||
|} | |} | ||
= Fazit = | |||
Der Modultest in MATLAB dient dazu, die korrekte Funktion von Programmen systematisch und automatisiert zu überprüfen. Im Zentrum steht das Unit-Test-Framework von MATLAB. | |||
Für wissenschaftliche Algorithmen, Signalverarbeitung und Simulink-Modelle ist MATLAB mit seinem Unit-Test-Framework besonders geeignet. | |||
Vorteile | |||
* frühzeitige Fehlererkennung | |||
* reproduzierbare Ergebnisse | |||
* sichere Weiterentwicklung | |||
* Dokumentation des Soll-Verhaltens | |||
* Grundlage für kontinuierliche Integration | |||
Aktuelle Version vom 26. Juni 2026, 07:32 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 testPositiv(testCase)
testCase.verifyEqual(quadrat(3),9);
end
function testNegativ(testCase)
testCase.verifyEqual(quadrat(-4),16);
end
function testNull(testCase)
testCase.verifyEqual(quadrat(0),0);
end
end
end
Test ausführen
results = runtests('TestQuadrat');
Ausgabe:
Running TestQuadrat . Done TestQuadrat
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,ParameterCombination = "sequential") % Parameter werden sequentiell verglichen 0-0, 1-1, 2-4, 3-9
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 with properties: Name Passed Failed Incomplete Duration Details Totals: 3 Passed, 0 Failed, 0 Incomplete. 0.038418 seconds testing time.
ä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 = matlab.unittest.TestRunner.withTextOutput('Verbosity', matlab.unittest.Verbosity.Detailed);
Test ausführen
results = runner.run(suite)
Beispielausgabe (detaillierter Bericht)
Running TestAddiere Setting up TestAddiere Done setting up TestAddiere in 0 seconds Running TestAddiere/testPositive Done TestAddiere/testPositive in 0.0023986 seconds Running TestAddiere/testNegative Done TestAddiere/testNegative in 0.0016029 seconds Running TestAddiere/testMixed Done TestAddiere/testMixed in 0.0016074 seconds Tearing down TestAddiere Done tearing down TestAddiere in 0 seconds Done TestAddiere in 0.0056089 seconds
Test-Suite sichern und laden
Test-Suite sichern
suite = testsuite(pwd); save suite.mat suite
Test-Suite laden
load suite.mat results = run(suite);
Test Browser

Der MATLAB Test Browser ist eine grafische Oberfläche des MATLAB Unit Test Frameworks, mit der sich automatisierte Tests komfortabel verwalten und ausführen lassen. Er bietet einen schnellen Überblick über vorhandene Testdateien, Testklassen und Testmethoden und ermöglicht die gezielte Auswahl einzelner oder mehrerer Tests. Die Ergebnisse werden übersichtlich dargestellt, sodass erfolgreiche, fehlgeschlagene oder übersprungene Tests leicht erkannt und analysiert werden können. Dadurch unterstützt der Test Browser Entwickler dabei, die Qualität und Zuverlässigkeit von MATLAB-Code sicherzustellen und Fehler frühzeitig zu erkennen, ohne Tests ausschließlich über die Kommandozeile ausführen zu müssen.
Sie finden ihn im Panel ab R2025a in dem auch der Copilot Chat zu finden ist.
Praktische Übung
Aufgabe 11.1
Implementieren Sie:
function y = cube(x)
Erstellen Sie mindestens drei Unit-Tests.
| Testklasse TestCube.m |
classdef TestCube ...
< matlab.unittest.TestCase
methods(Test)
function testConstantSignal(testCase)
x = -5:5;
y = cube(x);
testCase.verifyEqual(y,x^3);
end
end
end
|
Aufgabe 11.2
Entwickeln Sie Tests für:
function y = celsius2fahrenheit(x)
Prüfen Sie:
- 0 °C
- 100 °C
- −40 °C
| celsius2fahrenheit.m |
function F = celsius2fahrenheit(C)
F = C*9/5 + 32;
end
|
| Testklasse TestCelsius2Fahrenheit.m |
classdef TestCelsius2Fahrenheit < matlab.unittest.TestCase
properties(TestParameter)
C = {-40,0,100};
F = {-40,32,212};
end
methods(Test)
function testConversion(testCase,C,F)
testCase.verifyEqual( ...
celsius2fahrenheit(C), ...
F);
end
end
end
|
Aufgabe 11.3 – Butterworth-Tiefpassfilter
Ein Butterworth-Tiefpassfilter 2. Ordnung soll getestet werden.
Entwickeln Sie einen Test, der nachweist:
- Ein konstantes Signal bleibt konstant.
- Die Ausgangslänge entspricht der Eingangslänge.
| TiefpassFilter.m |
function y = TiefpassFilter(x)
fs = 100;
fc = 5;
n = 2;
[b,a] = butter(n,fc/(fs/2));
y = filter(b,a,x);
end
|
| Testklasse TestTiefpassFilter |
classdef TestTiefpassFilter < matlab.unittest.TestCase
methods(Test)
function testLength(testCase)
x = rand(1,1000);
y = lowpassFilter(x);
testCase.verifyEqual( ...
length(y), ...
length(x));
end
function testConstantSignal(testCase)
x = ones(1,1000);
y = lowpassFilter(x);
testCase.verifyEqual(y(end),1,'AbsTol',1e-2);
end
end
end
|
Aufgabe 11.4 – Testklasse entwickeln
Gegeben:
function y = addiere(a,b)
y = a+b;
end
Erstellen Sie eine vollständige Testklasse mit mindestens vier Testfällen.
| Testklasse TestAddierer.m |
classdef TestAddiere < matlab.unittest.TestCase
methods(Test)
function testPositive(testCase)
testCase.verifyEqual(addiere(3,4), 7);
end
function testNegative(testCase)
testCase.verifyEqual(addiere(-2,-3), -5);
end
function testZero(testCase)
testCase.verifyEqual(addiere(0,0), 0);
end
function testMixed(testCase)
testCase.verifyEqual(addiere(-2,5),3);
end
end
end
|
Aufgabe 11.5 – Fehlerbehandlung testen
Für die Funktion
function y = wurzel(x)
soll ein Fehler bei negativen Werten ausgelöst werden.
- Implementieren Sie die Funktion.
- Schreiben Sie den entsprechenden Unit-Test.
| Funktion wurzel.m |
function y = wurzel(x)
if x < 0
error('MATLAB:NegativeInput', ...
'Nur positive Werte erlaubt');
end
y = sqrt(x);
end
|
| Testklasse TestWurzel.m |
classdef TestWurzel < matlab.unittest.TestCase
methods(Test)
function testPositive(testCase)
testCase.verifyEqual(wurzel(9),3);
end
function testError(testCase)
testCase.verifyError( ...
@() wurzel(-5), ...
'MATLAB:NegativeInput');
end
end
end
|
Aufgabe 11.6 – Signalverarbeitung
Eine Filterfunktion soll getestet werden.
Prüfen Sie:
- Ausgangslänge
- Konstantes Eingangssignal
- Keine NaN-Werte im Ergebnis
Implementieren Sie die Tests mit verifyEqual, verifyTrue und verifyFalse.
| Funktion Butterworth.m |
function y = Butterworth(x)
[b,a] = butter(2,0.1);
y = filter(b,a,x);
end
|
| Testklasse TestButterworth.m |
classdef TestButterworth < matlab.unittest.TestCase
methods(Test)
function testOutputLength(testCase)
x = rand(1,1000);
y = myFilter(x);
testCase.verifyEqual(length(y),length(x));
end
function testConstantSignal(testCase)
x = ones(1,1000);
y = myFilter(x);
testCase.verifyEqual(y(end),1,'AbsTol',1e-2);
end
function testNoNaN(testCase)
x = rand(1,1000);
y = Butterworth(x);
testCase.verifyFalse(any(isnan(y)));
end
end
end
|
Fazit
Der Modultest in MATLAB dient dazu, die korrekte Funktion von Programmen systematisch und automatisiert zu überprüfen. Im Zentrum steht das Unit-Test-Framework von MATLAB.
Für wissenschaftliche Algorithmen, Signalverarbeitung und Simulink-Modelle ist MATLAB mit seinem Unit-Test-Framework besonders geeignet.
Vorteile
- frühzeitige Fehlererkennung
- reproduzierbare Ergebnisse
- sichere Weiterentwicklung
- Dokumentation des Soll-Verhaltens
- Grundlage für kontinuierliche Integration
→ MATLAB® Befehlsübersicht
→ zurück zum Hauptartikel: BSE Modellierung und Simulation - SoSe26