mikrocontroller.net

Forum: Compiler & IDEs Teststrategien für Embedded Devices


Autor: 0undNichtig (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: 0undNichtig (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :/

Autor: Uhu Uhuhu (uhu)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: StinkyWinky (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: StinkyWinky (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: 0undNichtig (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: StinkyWinky (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
TS_RegsHC11 RegsHC11;

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

Dank entsprechender Makros sind auch folgende Varianten möglich:
RegsHC11.U_PORTG._PORTG = InvState[InvStateIdx];
PORTG = InvState[InvStateIdx];
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:
unsigned char GetKey()
{
  unsigned char Key=0;

  switch (G_TestIdx)
  {
    case 0:
    case 1:
    case 3:
    case 4:
    case 11:
      // führe hier geeignete Tests durch
      // CU_ASSERT_xxx
      Key = K_DOWN;  // liefere den simulierten Tastendruck
      G_TestIdx++;   // nächster Test-Index
      break;
    case 9:
      // führe hier geeignete Tests durch
      // CU_ASSERT_xxx
      Key = K_LEFT;  // liefere den simulierten Tastendruck
      G_TestIdx++;   // nächster Test-Index
      break;
    case 13:
      // führe hier geeignete Tests durch
      // CU_ASSERT_xxx
      Key = K_EXIT;  // genug jetzt
      G_TestIdx++;   // nächster Test-Index
      break;
    default:
      // führe hier geeignete Tests durch
      // CU_ASSERT_xxx
      G_TestIdx++;   // nächster Test-Index
    break;
  }
  return Key;
}

Die Originalfunktion muss leider mittels bedingter Kompilation 
stillgelegt werden und kann nicht getestet werden.
#ifndef GCC_CUNIT_TEST_COMPILATION 
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.

Autor: 0undNichtig (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :-/

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.