Forum: Compiler & IDEs Teststrategien für Embedded Devices


von 0undNichtig (Gast)


Lesenswert?

Hallo Bastler!
Da ich nun schon einige Libs für mich entwickelt habe, stellt sich mir 
mitlerweile die Frage ob man nicht auch die Tests automatesieren könnte. 
Mi geht es also nicht darum die Hardware zu testen sondern eher per 
Modultest die Funktionsfähigkeit von einzelnen Funktionen auch nach 
Änderungen zu verifizieren.

Laut Wikipedia gibt es ja z.B. CUnit für die Überprüfung aber ich kann 
mir nicht vorstellen, wie das mit einem qC funzen soll. Irgendwie muss 
es ja eine Rückkopplung geben, ob Daten wirklich ausgegeben, Timing 
eingehalten wird, Leds leuchten,...

Darüber hinaus würde es mich auch interessieren, wenn man auf einem qC 
komplexe Dinge wie TCP/IP, RTOS, ... einsetzt, wie man dann den Stack 
testen kann um BufferOverflows und damit auftretende Sicherheitsprobleme 
zu umschiffen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

0undNichtig wrote:

> Laut Wikipedia gibt es ja z.B. CUnit für die Überprüfung aber ich kann
> mir nicht vorstellen, wie das mit einem qC funzen soll. Irgendwie muss
> es ja eine Rückkopplung geben, ob Daten wirklich ausgegeben, Timing
> eingehalten wird, Leds leuchten,...

LEDs wirst du wohl eher nicht in einer Bibliothek leuchten lassen.

Ansonsten kann man solche Dinge mit scriptfähigen Simulatoren testen.
Ist aber ein ziemlicher Aufwand.

von 0undNichtig (Gast)


Lesenswert?

Naja also nutzt keiner im hobby/semiprofesionellen Bereich automatische 
Tests?
Ich hatte dann noch https://sourceforge.net/projects/embunit/ Embedded 
Unit gefunden, scheint aber auch nicht so das wahre zu sein :/

von Uhu U. (uhu)


Lesenswert?

0undNichtig wrote:
> Naja also nutzt keiner im hobby/semiprofesionellen Bereich automatische
> Tests?

Das wäre wohl für erstere 1000facher Overkill, denn der Aufwand, 
automatische Tests zu programmieren, ist erheblich. Selbst im Bereich 
professioneller Software wird das durchaus nicht immer gemacht - 
Testdeppen sind billiger...

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Tests für einzelne Funktionen wie Parser, komplexe Berechnungen oder 
Regelschleifen sind sehr sinnvoll um Fehler zu vermeiden und nicht 
schwierig zu implementieren. Entweder man kompiliert sie direkt auf dem 
PC, führt sie (falls Assemblercode enthalten ist) mit einem Simulator 
aus, oder in einem Testprogramm direkt auf dem Controller (der kann dann 
den Testbericht z.B. über RS232 zum PC senden). Hilfreich ist es dabei 
auch den eigentlichen Code schon mit assert()ions zu spicken damit 
Ungereimtheiten sofort auffallen. So kann man auch einen TCP/IP-Stack 
oder ein RTOS in gewissen Grenzen testen. CUnit oder andere Frameworks 
braucht man dazu nicht unbedingt, die bringen nur zusätzliche und oft 
unnötige Komplexität mit ins Spiel.

Das Gesamtprogramm inkl. I/O und Timing zu testen ist dagegen sehr 
aufwendig. Einmal weil man die externe Hardware nachbilden bzw. 
überwachen muss, und weil man das gewünschte Verhalten überhaupt erst 
mal exakt spezifizieren muss. Das lohnt sich im semiprofessionellen 
Bereich sicher nicht.

von StinkyWinky (Gast)


Lesenswert?

Es gibt mehrere Ansätze:
1. Testcode direkt auf dem Target
2. Target-Code auf dem PC testen

Da ich für 1. zu wenig Programmspeicher hatte, habe ich mich für 2. 
entschieden. Ich teste mein Projekt mit cunit und Code::Blocks auf dem 
PC.

Und ja, ich kann SW-mässig testen, ob meine LEDs richtig angesteuert 
werden!
Genaugenommen teste ich natürlich nur den Wert in den Port-Registern, 
aber das genügt vollkommen.

von StinkyWinky (Gast)


Lesenswert?

Das mit dem korrekten Timing erachte ich als weniger wichtig.

Wenn ich z.B die Implementation meiner I2C-Sende-Routine testen will, 
prüfe ich, ob die gewünschten Daten in der richtigen Reihenfolge 
generiert werden. Da die Bytes teilweise erst gesendet werden, wenn der 
Slave geantwortet hat, wird diese Antwort natürlich (per SW) simuliert. 
Wie schnell die Geschichte abläuft, interessiert hier nicht.
Das Timing der I2C-Schnittstelle wird durch die I2C-Register festgelegt. 
Diese Einstellungen können wiederum per Unit-Test sichergestellt werden.

Schade wäre es, unter dem Vorwand des nicht korrekten Timings, die 
Unit-Tests von vornherein wegzulassen.

von 0undNichtig (Gast)


Lesenswert?

Wow das klingt eigentlich genau nach dem was ich will aber ich denke so 
ganz 0815 sieht das nicht aus oder? Kannst du das mal ein wenig 
ausführen evtl. mit Minicodeschnipsel?

von StinkyWinky (Gast)


Lesenswert?

Mein Vorgehen:

- Projekt in IDE Deiner Wahl erzeugen, alle Dateien des Zielsystems 
einbinden, ausser der main.c
- eigene main.c erstellen, welche den Code aus cunit aufnimmt

Jetzt erst mal alle Compiler-Fehler beseitigen. Das Problem mit den 
Ports und Registern des Zielsystems (HC11) habe ich so gelöst:
Da bereits eine Struktur TS_RegsHC11 in der Datei „hc11f_r.h“ existiert, 
brauchte ich nichts weiter zu tun, als an geeigneter Stelle im Testcode 
eine globale Instanz zu erzeugen:
1
TS_RegsHC11 RegsHC11;

Nun kann man die HW-Register beliebig beschreiben oder lesen, z.B.:
1
PPROG =  PPROG | 0x16;
2
printf("\n _PPROG = %d\n", RegsHC11.U_PPROG. _PPROG);

Dank entsprechender Makros sind auch folgende Varianten möglich:
1
RegsHC11.U_PORTG._PORTG = InvState[InvStateIdx];
2
PORTG = InvState[InvStateIdx];
3
G_PortG = InvState[InvStateIdx];

Wahrscheinlich wirst Du nicht umhinkommen, und gewisse Funktionen 
mittels bedingter Compileranweisung für den Test zu deaktivieren, bzw. 
durch eine spezielle Testfunktion zu ersetzen. Beispielsweise wenn Du 
Rückmeldungen der HW simulieren willst, wie z.B. ein Eingabegerät mit 
Tasten.
Nehmen wir an, du möchtest die Fuktion ZeigeInfo() testen. Das 
Zielsystem pollt mit er Funktion GetKey() auf einen Tastendruck:

main            UI        HwDriver
 ¦  ZeigeInfo()  ¦            ¦
 ¦-------------->¦ GetKey()   ¦
 ¦               ¦----------->¦
 ¦               ¦   Key N    ¦
 ¦               ¦<-----------¦
 ¦               ¦ GetKey()   ¦
 ¦               ¦----------->¦
 ¦               ¦   Key Exit ¦
 ¦               ¦<-----------¦
 ¦<--------------¦            ¦

Nun erstellst Du im TestCode eine eigene Funktion GetKey() mit der 
gleichen Signatur wie das Original, welche bei jedem Aufruf, abhängig 
von einem globalen Test-Status G_TestIdx, den gewünschten Key 
zurückliefert:
1
unsigned char GetKey()
2
{
3
  unsigned char Key=0;
4
5
  switch (G_TestIdx)
6
  {
7
    case 0:
8
    case 1:
9
    case 3:
10
    case 4:
11
    case 11:
12
      // führe hier geeignete Tests durch
13
      // CU_ASSERT_xxx
14
      Key = K_DOWN;  // liefere den simulierten Tastendruck
15
      G_TestIdx++;   // nächster Test-Index
16
      break;
17
    case 9:
18
      // führe hier geeignete Tests durch
19
      // CU_ASSERT_xxx
20
      Key = K_LEFT;  // liefere den simulierten Tastendruck
21
      G_TestIdx++;   // nächster Test-Index
22
      break;
23
    case 13:
24
      // führe hier geeignete Tests durch
25
      // CU_ASSERT_xxx
26
      Key = K_EXIT;  // genug jetzt
27
      G_TestIdx++;   // nächster Test-Index
28
      break;
29
    default:
30
      // führe hier geeignete Tests durch
31
      // CU_ASSERT_xxx
32
      G_TestIdx++;   // nächster Test-Index
33
    break;
34
  }
35
  return Key;
36
}

Die Originalfunktion muss leider mittels bedingter Kompilation 
stillgelegt werden und kann nicht getestet werden.
1
#ifndef GCC_CUNIT_TEST_COMPILATION 
2
unsigned char GetKey()

Im Testcode zu ZeigeInfo() brauchst Du die Variable TestIdx richtig zu 
setzen und rufst ZeigeInfo() auf, welche die obigen Tests durchfürt und 
durch den simulierten ExitKey wieder zurückkommt.

von 0undNichtig (Gast)


Lesenswert?

Danke für die ausführliche Beschreibung, genau so die Richtung dachte 
ich mir!

Wobei mir beim lesen wieder mal aufgefallen sit, dass durch die bedingte 
Kompilierung ebend der Code für außenstehende nur sehr schlecht lesbar 
wird :-/

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.