Login| Sign Up| Help| Contact|

Patent Searching and Data


Title:
METHOD FOR TESTING A COMPUTER PROGRAM PROGRAMMED IN AN OBJECT-ORIENTED SCRIPTING LANGUAGE, AND SYSTEM, COMPUTER PROGRAM AND COMPUTER-READABLE STORAGE MEDIUM
Document Type and Number:
WIPO Patent Application WO/2024/088781
Kind Code:
A1
Abstract:
The invention relates to a method for testing a computer program programmed in an object-oriented scripting language, comprising the following steps: - providing a computer program part for generating abstract classes (2); - providing at least one abstract class (2), which comprises at least one abstract member (3, 4), by means of the computer program part; - providing a class (9) which inherits from the abstract class (2) and which comprises only non-abstract members (10, 11); - generating an object derived from the inheriting class (9), the object therefore constituting a reference to the abstract class (9), - wherein properties of the non-abstract members (10, 11) are compared with the properties of the abstract members (3, 4); and - if there is at least one abstract member (3, 4) of the abstract class (2) for which no non-abstract member (10, 11) of the inheriting class (9) having the same properties is found, an entry is generated in an error list and said error list is then output as an error message.

Inventors:
NETZEBAND ANDRÉ (DE)
Application Number:
PCT/EP2023/078431
Publication Date:
May 02, 2024
Filing Date:
October 12, 2023
Export Citation:
Click for automatic bibliography generation   Help
Assignee:
VOLKSWAGEN AG (DE)
International Classes:
G06F11/36; G06F9/46
Foreign References:
US20070256055A12007-11-01
US7536679B12009-05-19
Download PDF:
Claims:
Patentansprüche Verfahren zum Testen eines in einer objektorientierten Skriptsprache programmierten Computerprogramms, aufweisend folgende Schritte:

Bereitstellen eines Computerprogrammteils zur Erzeugung abstrakter Klassen (2);

Bereitstellen wenigstens einer abstrakten Klasse (2), welche mindestens ein abstraktes Mitglied (3, 4), insbesondere nur abstrakte Mitglieder, aufweist, mittels des Computerprogrammteils;

Bereitstellen einer von der abstrakten Klasse (2) erbenden Klasse (9), die nur nicht abstrakte Mitglieder (10, 11) aufweist;

Erzeugen eines von der erbenden Klasse (9) abgeleiteten Objektes, wodurch dieses eine Referenz auf die abstrakte Klasse (9) darstellt,

- wobei Eigenschaften der nicht abstrakten Mitglieder (10, 11) der erbenden Klasse (9) mit den Eigenschaften der abstrakten Mitglieder (3, 4) der abstrakten Klasse (2) verglichen werden; und falls es mindestens ein abstraktes Mitglied (3, 4) der abstrakten Klasse (2) gibt für welches kein nicht abstraktes Mitglied (10, 11) der erbenden Klasse (9) mit den gleichen Eigenschaften gefunden wird, wird ein Eintrag in einer Fehlerliste erzeugt und diese dann als Fehlermeldung ausgegeben. Verfahren nach Anspruch 1 , aufweisend folgende weitere Schritte:

Überprüfen bei allen von einer Softwarekomponente des Computerprogramms referenzierten Objekten, ob das jeweilige referenzierte Objekt eine Referenz auf die zugehörige abstrakte Klasse (2) darstellt; und falls wenigstens ein überprüftes von einer Softwarekomponente referenzielles Objekt nicht die Referenz auf die zugehörige Klasse (2) darstellt, wird eine weitere Fehlermeldung ausgegeben. Verfahren nach Anspruch 1 oder 2, wobei folgende Eigenschaften verglichen werden:

Namen der Mitglieder (3, 4, 10, 11),

Typ und Datentyp (5, 12) des jeweiligen Mitgliedes (3, 4, 10 ,11), und

- Argumente (6, 13) des jeweiligen Mitgliedes (4, 11), und

Datentyp (7, 14) des jeweiligen Arguments (6, 13) des Mitglieds (4, 11), und Datentyp (8, 15) eines Rückgabewertes, Verfahren nach einem der vorhergehenden Ansprüche, wobei zu jeder erbenden Klasse (9) des Computerprogramms ein Objekt vor Durchführen eines Hauptteils des Computerprogramms erzeugt wird und überprüft wird, ob die jeweilige Erzeugung erfolgreich ist. Verfahren nach einem der vorhergehenden Ansprüche, wobei alle Softwarekomponenten des Computerprogrammes, insbesondere nur, von abstrakten Klassen (2) abhängig sind, wobei Abhängigkeiten der Softwarekomponenten, insbesondere solche, die von den abstrakten Klassen (2) erben, zentral erzeugt und übergeben werden. Verfahren nach einem der vorhergehenden Ansprüche, wobei das Computerprogramm in einer Python Programmiersprache programmiert und getestet wird. Verfahren zum Ausführen eines Computerprogramms, bei welchem ein Testen des Computerprogramms vor einer Ausführung eines Hauptteils des Computerprogramms nach einem der vorhergehenden Ansprüche 1 bis 6 durchgeführt wird, und falls ein Eintrag in die Fehlerliste erfolgt oder eine Fehlermeldung ausgegeben wird, das Ausführen des Hauptteils verhindert wird, und falls kein Eintrag in die Fehlerliste erfolgt oder eine Fehlermeldung ausgegeben wird, der Hauptteil des Computerprogramms, insbesondere automatisch, gestartet wird, und/oder das Verfahren nach einem der vorhergehenden Ansprüche 1 bis 6 bei einem bereits gestarteten Ausführen des Hauptteils zumindest einmal durchgeführt wird, insbesondere dann durchgeführt wird, wenn ein von einer erbenden Klasse (9) abgeleitetes Objekt erzeugt wird. System zur Durchführung eines Verfahrens, aufweisend Mittel zur Ausführung der Schritte des Verfahrens nach einem der vorhergehenden Ansprüchen. Computerprogramm, welches nach einem Verfahren nach einem der Ansprüche nach 1 bis 6 getestet ist und in eine Speichereinheit ladbar ist und durch einen Prozessor ausführbar ist. Computerlesbares Speichermedium, aufweisend Befehle, die bei der Ausführung durch einen Computer diesen veranlassen, die Schritte des Verfahrens nach einem der Ansprüche 1 bis 7 auszuführen.

Description:
Beschreibung

Verfahren zum Testen eines in einer objektorientierten Skriptsprache programmierten Computerprogramms sowie System, Computerprogramm und computerlesbares Speichermedium

Ein Aspekt der Erfindung betrifft ein Verfahren zum Testen eines in einer objektorientierten Skriptsprache programmierten Computerprogramms.

Es sind objektorientierte Programmiersprachen bekannt, welche mit dem Konzept eines Interfaces und der Injektion von Abhängigkeiten (Dependency Injection) arbeiten. Interfaces sind abstrakte Klassen, welche ausschließlich abstrakte Methoden und abstrakte Attribute aufweisen. Diese Programmiersprachen weisen einen Kompilierer (Compiler) auf, welcher einen geschriebenen Programmcode vor Ausführung des Programmcodes kompiliert. Dabei wird der Programmcode auf Fehler hin überprüft und in Maschinencode übersetzt. Der Kompilierer überprüft zu einer Kompilierzeit, ob alle Interfaces und Zuweisungen innerhalb eines Programms konsistent sind. Dadurch laufen Programme, die auf kompilierten Programmcode basieren, ausfallsicher, da Fehler bereits vor der Ausführung erkannt werden.

Bei Skriptsprachen, welche nicht kompiliert werden, treten Fehler erst zur Laufzeit auf. Skriptsprachen bieten aber andere Vorteile gegenüber Programmiersprachen, die kompiliert werden.

Daher liegt der Erfindung die Aufgabe zugrunde Vorteile von kompilierten Programmiersprachen für Skriptsprachen zu ermöglichen.

Die Aufgabe wird durch die Gegenstände der unabhängigen Patentansprüche gelöst. Vorteilhafte Weiterbildungen der Erfindung sind durch die abhängigen Patentansprüche, die folgenden Beschreibung sowie der Figur beschrieben.

Ein Aspekt der Erfindung betrifft ein Verfahren zum Testen eines in einer objektorientierten Skriptsprache programmierten Computerprogramms, vorzugsweise aufweisend folgende Schritte: Bereitstellen eines Computerprogrammteils zur Erzeugung abstrakter Klassen; Bereitstellen wenigstens einer abstrakten Klasse, welche mindestens ein abstraktes Mitglied, insbesondere nur abstrakte Mitglieder, aufweist, mittels des Computerprogrammteils;

Bereitstellen einer von der abstrakten Klasse erbenden Klasse, die nur nicht abstrakte Mitglieder aufweist;

Erzeugen eines von der erbenden Klasse abgeleiteten Objektes, wodurch dieses eine Referenz auf die abstrakte Klasse darstellt, wobei Eigenschaften der nicht abstrakten Mitglieder der erbenden Klasse mit den Eigenschaften der abstrakten Mitglieder der abstrakten Klasse verglichen werden; und falls es mindestens ein abstraktes Mitglied der abstrakten Klasse gibt für welches kein nicht abstraktes Mitglied der erbenden Klasse mit den gleichen Eigenschaften gefunden wird, wird ein Eintrag in einer Fehlerliste erzeugt und diese dann als Fehlermeldung ausgegeben.

Insbesondere kann es sich bei dem vorgeschlagenen Verfahren um ein computerimplementiertes Verfahren handeln. Insbesondere wird das Verfahren auf einer elektronischen Recheneinheit ausgeführt. Das getestete Computerprogramm kann auf dieser Recheneinheit oder nach Übertragung auf einer weiteren Recheneinheit ausgeführt werden. Durch das Ausführen des Computerprogramms kann ein Fahrzeug, insbesondere autonom, insbesondere teilautonom, gesteuert werden. Gegebenenfalls handelt es sich um ein Verfahren zum Betreiben einer elektronischen Recheneinheit. Insbesondere wird durch das Verfahren auch der Betrieb einer Recheneinheit verbessert. Insbesondere da somit auch die Recheneinheit fehlerminimierter, insbesondere somit auch schneller und effizienter, arbeiten kann. Insbesondere wird der Ablauf eines Computerprogramms auf einer Recheneinheit verbessert. Es ist also auch ein Verfahren zum Durchführen eines Ablaufs eines Computerprogramms auf einer Recheneinheit bereitgestellt.

Insbesondere handelt es sich um Skriptsprachen, welche keine eingebaute Typüberprüfung und/oder Schnittstellendefinition besitzen.

Der insbesondere neu und zusätzlich bereitgestellte Computerprogrammteil zur Erzeugung abstrakter Klassen ist nicht zwingend Teil des Computerprogramms. Er kann aber insbesondere dem Computerprogramm hinzugefügt werden. Der Computerprogrammteil kann insbesondere auch als Bibliothek in das Computerprogramm eingebunden werden. Handelt es sich bei der gewählten Programmiersprache beispielsweise um Python, kann dafür die Abstract Base Class (abc) Bibliothek eingebunden werden. Zumindest das Computerprogrammteil ermöglicht es nun, die genannten Schritte durchzuführen und somit ein herkömmliches, in einer objektorientierten Skriptsprache programmierten Computerprogramm im Hinblick auf Fehlergenerierung und Fehlererkennung zu verbessern. Somit ist es nun möglich, solche Computerprogramme mit ihren Vorteilen im Vergleich zu compilerbasierten Computerprogrammen zu nutzen und dennoch die bessere Analysefähigkeit im Hinblick auf Fehlererkennung, wie sie bei compilerbasierten Computerprogrammen vorhanden ist, anzubieten.

Abstrakte Klassen sind in der objektorientierten Programmierung Klassen, welche mindestens eine abstrakte Methode oder mindestens ein abstraktes Attribut aufweisen. Methoden und Attribute einer Klasse können als Mitglieder der Klasse (member) bezeichnet werden. Interfaces sind ein Spezialfall abstrakter Klassen. Sie weisen regulär nur abstrakte Mitglieder auf, das bedeutet, sie weisen beispielsweise nur abstrakte Methoden und abstrakte Attribute auf. Ein Interface kann als Vertrag verstanden werden, der beschreibt, welche Mitglieder eine Klasse haben soll. Ein abstraktes Mitglied ist insbesondere ein Mitglied (member), welches keine Implementierung, sondern nur eine Definition, welche als Signatur bezeichnet werden kann, benutzt. Beispielsweise wird erst durch ein Vorhandensein mindestens eines abstrakten Mitglieds eine Klasse zu einer abstrakten Klasse. Eine abstrakte Klasse kann allgemein auch nicht abstrakte Mitglieder besitzen. Ein Interface in der Regel jedoch nicht.

Insbesondere wird eine abstrakte Klasse bereitgestellt, insbesondere programmiert, insbesondere dem Computerprogramm hinzugefügt. Insbesondere werden einige Interfaces, insbesondere nur Interfaces, bereitgestellt. Dazu wird insbesondere der Computerprogrammteil benutzt. Beispiele für einen Typ eines Mitglieds kann eine Methode, ein Attribut, eine Klassenmethode (Class Method) oder eine statische Methode (static Method) sein.

Beispielcode für Python: from happy. typing import Abstractclass, abstractmethod, typechecked

# Definition des Interfaces class ITest(AbstractClass):

@abstractmethod

@typechecked def foo(self, value:int) -> str:

©property

@abstractmethod def bar(self) -> float:

Durch diesen Beispielcode kann ein Interface als Spezialfall einer abstrakten Klasse bereitgestellt werden. Durch Ausführen dieses Beispielcodes wird insbesondere ein Interface erzeugt.

Nicht abstrakte Klassen können von abstrakten Klassen, insbesondere von Interfaces erben. Dabei müssen alle Mitglieder der abstrakten Klasse von der erbenden Klasse realisiert werden, sodass jedem abstraktem Mitglied der abstrakten Klasse ein nicht abstraktes Mitglied der erbenden Klasse mit den, insbesondere gleichen, Eigenschaft zugeordnet entspricht. Eine Klasse kann ein Interface realisieren, indem sie von ihr erbt und die entsprechenden Mitglieder mit einer echten Implementierung überschreibt. Eine Realisierung ist insbesondere die konkrete Implementierung zu einem Interface. Insbesondere müssen alle zuvor abstrakten Mitglieder tatsächlich implementiert sein. Eine Klasse kann eine Realisierung mehrerer Interfaces darstellen.

Beispielcode für Python:

# korrekte Realisierung dass cTest(ITest):

@typechecked def foo(self, value:int) -> str:

... # Hier erfolgt die Implementierung

©property def bar(self) -> float:

... # Hier erfolgt die Implementierung

Von der erbenden Klasse kann ein Objekt abgeleitet und erzeugt werden. Dies kann als Instanziierung der erbenden Klasse bezeichnet werden. Dadurch erhält das Objekt eine Referenz auf die abstrakte Klasse, insbesondere auf das Interface, von der die erbende Klasse erbt. Insbesondere ist eine Referenz eine Art Adresse, unter der ein Objekt angesprochen werden kann. Bei manchen Programmiersprachen ist es möglich, dass Referenzen direkt durch Speicheradressen dargestellt werden. Bei Python beispielsweise ist dies nicht der Fall. Wird eine Klasse instanziiert, wird insbesondere das Objekt im Speicher der Recheneinheit, insbesondere eines Computers, angelegt. Insbesondere wird anschließend dieses Objekt in Form einer Referenz an Funktionen oder andere Klassen weitergeleitet, so dass diese drauf zugreifen können. Gegebenenfalls reicht die Speicheradresse nicht für einen Zugriff, sondern es wird zusätzlich eine Information benötigt, um welches Objekt es sich handelt. Dabei ist es beispielsweise nötig, die zugehörige Klasse des Objektes für einen Zugriff zu übergeben. Dann ist es möglich, das Objekt über die Referenz korrekt anzusprechen. Gemäß des erfindungsgemäßen Verfahren stellt das Objekt die Referenz auf die abstrakte Klasse, insbesondere auf das Interface, dar. Dadurch, dass die Referenz des Objekts auf die abstrakte Klasse, insbesondere das Interface verweist, kann es über die Methoden und Attribute des Interfaces von außen angesprochen werden. Insbesondere ist es deshalb wichtig, dass Mitglieder des Interfaces den Mitgliedern der erbenden Klasse bezüglich ihrer Eigenschaften korrekt und vollständig vererbt, insbesondere implementiert, werden. Dadurch kann eine lose Kopplung zwischen Softwarekomponenten erreicht werden. Eine Softwarekomponente, die ein Objekt einer erbenden Klasse benutzt, bekommt nur das nötigste mitgeteilt, um das Objekt zu nutzen. Eine solche Softwarekomponente kann als Client bezeichnet werden und das Objekt als Service. Ein Client, der eine andere Klasse oder eine Funktion sein kann, kann von dem Interface abhängen anstatt von einer bestimmten Klasse. Dies ermöglicht es, die Implementierung später durch eine andere Klasse zu ersetzen, die das gleiche Interface realisiert. Dadurch entsteht eine lose Kopplung zwischen Klassen. Der Softwarecode kann dadurch modularer aufgebaut werden und ist damit leichter zu pflegen. Außerdem ist der Softwarecode dadurch leichter wiederverwendbar, insbesondere in verschiedenen Kontexten.

Beispielcode für Python: c = CT est()

Insbesondere wird der Vergleich der Eigenschaften der abstrakten Mitglieder mit den Eigenschaften der nicht abstrakten Mitglieder durch die Instanziierung ausgelöst. Insbesondere wird der Vergleich für alle abstrakten Mitglieder mit allen nicht abstrakten Mitgliedern durchgeführt. Insbesondere wird der Vergleich durch die Instanziierung ausgelöst, wenn ein weiterer Computerprogrammteil, insbesondere eine eingebundene Bibliothek, dies ermöglicht. Insbesondere wird der Vergleich ohne den weiteren Computerprogrammteil nicht ausgelöst. Insbesondere wird durch das Verfahren überprüft, ob eine Instanz überhaupt in der Lage ist ein Interface zu realisieren.

Das Verfahren ist besonders vorteilhaft, da es eine Verwendung gängiger Software- Engineering Konzepte wie „Dependency Injection“ sowie zahlreicher objektorientierter Pattern (oop Pattern) ermöglicht oder erleichtert. Insbesondere in der Programmiersprache Python ist das Konzept von der Verwendung von Interfaces prinzipiell unbekannt. Daher kann in Python bisher nicht überprüft werden, ob eine Realisierung konsistent ist und/oder ob eine übergebene Referenz mit dem Interface kompatibel ist.

Tritt beispielsweise beim Vergleich ein Fehler auf, wird ein Eintrag in eine Fehlerliste erzeugt. Als Fehler wird beispielsweise erkannt, wenn nicht alle abstrakten Mitglieder der abstrakten Klasse, insbesondere des Interfaces, jeweils einem nicht abstrakten Mitglied der erbenden Klasse zugeordnet werden können. Dann wird, insbesondere die Fehlerliste, als eine Fehlermeldung ausgegeben. Das Ausgeben der Fehlerliste kann bedeuten, dass die Fehlerliste einem Benutzer, akustisch oder visuell, insbesondere auf einem Bildschirm angezeigt wird. Die Fehlerliste kann alternativ dazu oder zusätzlich an ein externes System ausgegeben bzw. zur Verfügung gestellt werden. Insbesondere enthält die Fehlerliste eine Angabe welche Eigenschaften welcher Mitglieder nicht übereinstimmen.

In einem Ausführungsbeispiel weist das Verfahren folgende weitere Schritte auf: Überprüfen bei allen von einer Softwarekomponente des Computerprogramms referenzierten Objekten, ob das jeweilige referenzierte Objekt eine Referenz auf die zugehörige abstrakte Klasse darstellt; und falls wenigstens ein überprüftes von einer Softwarekomponente referenzielles Objekt nicht die Referenz auf die zugehörige Klasse darstellt, wird eine weitere Fehlermeldung ausgegeben.

Insbesondere ist die zugehörige abstrakte Klasse, eine zu erwartende, insbesondere im Programmcode angegebene, abstrakte Klasse. Insbesondere muss für jede Funktion oder Methode des Computerprogramms geprüft werden, ob die übergebenen Referenzen des Objektes (übergebene Objektreferenzen) Instanzen der erwarteten abstrakten Klassen sind. Sind sie das nicht, wird gegebenenfalls eine Fehlermeldung ausgegeben, insbesondere an einen Benutzer ausgegeben und/oder einem externen System zur Verfügung gestellt.

Die Überprüfung kann auch als Laufzeittypüberprüfung bezeichnet werden, da diese Überprüfung insbesondere zur Laufzeit stattfindet und dabei der Typ der abstrakten Klasse, die eine Referenz auf das Objekt aufweist, überprüft wird. Der Typ der abstrakten Klasse bezeichnet insbesondere den Namen der abstrakten Klasse.

Beispielcode in Python:

@typechecked def do_something(instance: Interface): instance. foo()

Insbesondere können durch die Überprüfung nur Objekte von der zu erwartenden Klasse, die eine abstrakte Klasse, insbesondere ein Interface, realisieren, als Argument an eine Funktion oder Methode übergeben werden. Insbesondere wird dadurch überprüft, ob eine Referenz formal einem zu erwartenden Interface zugeordnet werden kann.

Bei diesem Ausführungsbeispiel kann die Konsistenz des Computerprogramms sichergestellt werden. Dadurch ist es ausfallsicherer und weniger fehleranfällig.

In einem Ausführungsbeispiel werden folgende Eigenschaften der Mitglieder verglichen: Namen der Mitglieder,

Typ und Datentyp des jeweiligen Mitgliedes, und Argumente des jeweiligen Mitgliedes, und Datentyp des jeweiligen Arguments des Mitglieds, und Datentyp eines Rückgabewertes,

Der Typ eines Mitglieds bezeichnet beispielsweise, ob es sich bei dem Mitglied um ein Attribut oder um eine Methode handelt. Beim Vergleich der Argumente des Mitglieds wird insbesondere der Name und die Anzahl der Argumente einer Methode verglichen.

Argumente sind insbesondere Übergabeparameter. Insbesondere wird auch der jeweilige Datentyp der Argumente verglichen.

Insbesondere werden zusätzlich, insbesondere alle, Funktionsdekoratoren (function decorator) der Mitglieder verglichen. Insbesondere ist ein Funktionsdekorator eine Funktion, die eine andere Funktion aufnimmt und das Verhalten der letzteren Funktion erweitert, ohne sie explizit zu verändern. Insbesondere ist ein Funktionsdekorator eine Funktion, die eine andere Funktion umhüllt. Insbesondere sieht es von außen so aus, als ob die eigentliche Funktion aufgerufen wird, aber es wird zunächst der Dekorator ausgeführt, welcher dann intern die eigentliche Funktion ausführt und dann den Rückgabewert dieser ebenfalls zurück gibt. Kann für jedes abstrakte Mitglied der abstrakten Klasse, insbesondere des Interfaces, ein nicht abstraktes Mitglied der erbenden Klasse identifiziert werden, dass in allen Eigenschaften mit einem abstrakten Mitglied übereinstimmt, dann ist dieser Vergleich erfolgreich. Damit kann sichergestellt werden, dass die erbende Klasse eine korrekte Realisierung der abstrakten Klasse, insbesondere des Interfaces, ist. Dadurch ist das Computerprogramm ausfallsicherer und weniger fehleranfällig.

In einem Ausführungsbeispiel wird zu den, insbesondere zu jeder, erbenden Klasse des Computerprogramms ein Objekt vor Durchführen eines Hauptteils des Computerprogramms erzeugt. Es wird überprüft, ob die jeweilige Erzeugung erfolgreich ist.

Insbesondere kann dies als Modultest oder Unit-Test bezeichnet werden. Insbesondere löst das Erzeugen des Objektes, was auch als Instanziieren der erbenden Klasse bezeichnet werden kann, den Vergleich der Eigenschaften der abstrakten Mitglieder mit den Eigenschaften der nicht abstrakten Mitglieder aus. Ist der Vergleich nicht erfolgreich, dann kann auch das Objekt nicht erzeugt werden. Insbesondere wird dann eine Fehlermeldung ausgegeben.

Insbesondere können die Modultests, insbesondere für alle, erbenden Klassen automatisiert erstellt und/oder ausgeführt werden.

Als Hauptteil kann ein Programmteil des Computerprogramms bezeichnet werden, der beispielsweise dauerhaft ausgeführt wird solange das Computerprogramm läuft.

Insbesondere wird im Hauptteil des Computerprogramms Code ausgeführt, der nicht Teil des Modultests ist.

Beispielcode für Python: def test_create(self): instance = Class() assert isinstance(instance, Interface) assert isinstance(instance, Class)

Die letzten beiden Zeilen sind für den Modultest gegebenenfalls nicht notwendig. Sie erhöhen aber eine Sicherheit und Zuverlässigkeit der Konsistenz des Computerprogramms. Insbesondere wird in diesen beiden Zeilen überprüft, ob die erzeugte Instanz eine Instanz der erbenden Klasse ist, die eine abstrakte Klasse, insbesondere ein Interface, realisiert.

In einem Ausführungsbeispiel sind alle Softwarekomponenten des Computerprogrammes, insbesondere nur, von abstrakten Klassen abhängig. Die Abhängigkeiten der Softwarekomponenten, insbesondere solche, die von abstrakten Klassen erben, zentral erzeugt und übergeben.

Die vorteilhafte Weiterbildung dieses Ausführungsbeispiels kann als Einbringen von Abhängigkeiten (Dependecy Injection) bezeichnet werden. Als Dependency Injection kann in der objektorientierten Programmierung ein Entwurfsmuster bezeichnet werden, welches Abhängigkeiten eines Objekts zur Laufzeit reglementiert. Benötigt ein Objekt beispielsweise bei seiner Instanziierung ein anderes Objekt, ist diese Abhängigkeit an einem zentralen Ort hinterlegt, es wird also nicht vom initialisierten Objekt selbst erzeugt. Dieser zentrale Ort kann als Compositon Root bezeichnet werden. Insbesondere ist mit Ort eine Stelle im Computerprogramm gemeint.

Dabei ist es beispielsweise möglich, dass die Abhängigkeiten von anderen Klassen über Konstruktoren zur Verfügung gestellt werden. Dies kann als Constructor Dependency Injection bezeichnet werden.

Die Composition Root des Computerprogramms wird insbesondere direkt nach Start des Programms aufgerufen, insbesondere bevor der Hauptteil des Computerprogramms ausgeführt wird. Dadurch kann sichergestellt werden, dass die Abhängigkeiten bereits zu Beginn des Computerprogramms überprüft werden. Dadurch kann an dieser Stelle bereits bei allen von einer Softwarekomponente des Computerprogramms referenziellen Objekten überprüft werden, ob das jeweilige referenzierte Objekt eine Referenz auf die zugehörige, insbesondere erwartete, abstrakte Klasse aufweist.

So können Fehler vor Durchführen des Hauptteil festgestellt werden. Auch dadurch ist das Computerprogramm ausfallsicherer und weniger fehleranfällig.

In einem Ausführungsbeispiel wird das Computerprogramm in einer Python Programmiersprache programmiert und getestet. Diese Programmiersprache bietet viele Vorteile. Insbesondere gilt sie als Standard im Bereich Datenwissenschaft und maschinelles Lernen. Insbesondere wird Python 3 verwendet.

Ein weiterer Aspekt der Erfindung betrifft ein Verfahren zum Ausführen eines Computerprogramms. Dabei wird ein Testen des Computerprogramms vor einer Ausführung eines Hauptteils des Computerprogramms durchgeführt wird. Falls ein Eintrag in die Fehlerliste erfolgt oder eine Fehlermeldung ausgegeben wird, wird das Ausführen des Hauptteils verhindert. Falls kein Eintrag in die Fehlerliste erfolgt oder eine Fehlermeldung ausgegeben wird, wird der Hauptteil des Computerprogramms, insbesondere automatisch, gestartet. Zusätzlich oder alternativ dazu wird das erfindungsgemäße Verfahren zum Testen bei einem bereits gestarteten Ausführen des Hauptteils zumindest einmal durchgeführt, insbesondere dann durchgeführt, wenn ein von einer erbenden Klasse abgeleitetes Objekt erzeugt wird.

Wird der Hauptteil nicht ausgeführt, da ein Fehler vorliegt, kann dieser identifiziert und behoben werden. Insbesondere wird der Fehler durch das erfindungsgemäße Verfahren identifiziert und von dem externen System automatisiert behoben.

Bei Computerprogrammen, die in einer Skriptsprache, insbesondere ohne Kompilierer, programmiert werden und nicht durch das erfindungsgemäße Verfahren getestet werden, ist es möglich, dass Fehler erst während der Ausführung des Hauptteils auftreten. Es ist möglich, dass dies erst nach einigen Stunden oder später der Fall ist. Durch das erfindungsgemäße Verfahren werden Fehler vor der Ausführung des Hauptteils erkannt. Dadurch kann Zeit und Energie gespart werden, da kein fehlerhaftes Programm unnötig lange ausgeführt wird.

Das getestete Computerprogramm kann zur, insbesondere autonomen, insbesondere teilautonomen, Steuerung eines Fahrzeugs verwendet werden. Durch das erfindungsgemäße Testen wird eine Ausfallsicherheit des Computerprogramms erhöht. Durch die erhöhte Ausfallsicherheit kann ein sichererer Betrieb des Fahrzeugs gewährleistet werden.

Ein weiterer Aspekt der Erfindung betrifft ein System zur Durchführung eines Verfahrens, aufweisend Mittel zur Ausführung der Schritte des Verfahrens nach einem der vorhergehenden Ansprüchen. Das System kann eine elektronische Testeinheit und/oder eine elektronische Recheneinheit aufweisen. Ein weiterer Aspekt der Erfindung betrifft ein Computerprogramm, welches nach einem Verfahren gemäß dem oben genannten Aspekt getestet ist, insbesondere in eine Speichereinheit ladbar ist und durch einen Prozessor ausführbar ist.

Ein weiterer Aspekt der Erfindung betrifft ein computerlesbares Speichermedium, aufweisend Befehle, die bei Ausführung durch einen Computer diesen veranlassen, die Schritte des Verfahrens nach einem der Ansprüche 1 bis 7 auszuführen.

Weitere Ausführungsformen des erfindungsgemäßen Systems, des erfindungsgemäßen Computerprogramms und des erfindungsgemäßen Speichermediums folgen unmittelbar aus den verschiedenen Ausgestaltungen des erfindungsgemäßen Verfahrens und umgekehrt. Insbesondere lassen sich einzelne Merkmale und entsprechende Erläuterungen sowie Vorteile bezüglich der verschiedenen Ausführungsformen zu dem erfindungsgemäßen Verfahren analog auf entsprechende Ausführungsformen des erfindungsgemäßen Systems, des erfindungsgemäßen Computerprogramms und des erfindungsgemäßen Speichermediums übertragen. Insbesondere ist das erfindungsgemäße System, das erfindungsgemäße Computerprogramm und das erfindungsgemäße Speichermedium zum Durchführen eines erfindungsgemäßen Verfahrens ausgebildet oder programmiert. Insbesondere führt das erfindungsgemäße System, das erfindungsgemäße Computerprogramm und das erfindungsgemäße Speichermedium das erfindungsgemäße Verfahren durch.

Die Erfindung umfasst auch die Kombinationen der Merkmale der beschriebenen Ausführungsformen.

Im Folgenden werden Ausführungsbeispiele der Erfindung beschrieben. Hierzu zeigt:

Fig. 1 ein Klassendiagramm eines Ausführungsbeispiels eines Computerdiagramms;

Bei den im Folgenden erläuterten Ausführungsbeispielen handelt es sich um bevorzugte Ausführungsbeispiele der Erfindung. Bei den Ausführungsbeispielen stellen die beschriebenen Komponenten jeweils einzelne, unabhängig voneinander zu betrachtende Merkmale der Erfindung dar, welche die Erfindung jeweils auch unabhängig voneinander weiterbilden und damit auch einzeln oder in einer anderen als der gezeigten Kombination als Bestandteil der Erfindung anzusehen sind. Des Weiteren sind die beschriebenen Ausführungsbeispiele auch durch weitere der bereits beschriebenen Merkmale der Erfindung ergänzbar.

In der Figur sind funktionsgleiche Elemente jeweils mit denselben Bezugszeichen versehen.

In Fig. 1 ist ein beispielhaftes Klassendiagramm 1 eines Ausführungsbeispiels eines Computerprogramms gezeigt. Die abstrakte Klasse 2 „Interface“ kann ein Attribut 3, dass „Attribut“ heißt und eine Methode 4, die „Operation“ heißt, aufweisen. Alle Attribute und Methoden sind in diesem Ausführungsbeispiel abstrakt. Deshalb handelt es sich bei dieser abstrakten Klasse 2 um ein Interface 2. Das Attribut 3 ist in diesem Ausführungsbeispiel vom Datentyp String 5. Das Attribut 3 kann insbesondere eine Zeichenkette sein. Die Methode 4 „Operation“ erwartet einen Übergabeparameter 6 „Wert“ vom Datentyp String 7. Ein Rückgabewert der Methode 4 „Operation“ ist von einem booleschen Datentyp 8.

Die erbende Klasse 9 „erbende Klasse“ realisiert das Interface 2. Das bedeutet, dass auch die erbende Klasse 9 ein Attribut 10 „Attribut“ und eine Methode 11 „Operation“ aufweist. Gegebenenfalls weist die erbende Klasse 9 noch weitere Attribute und Methoden auf. Gegebenenfalls erbt sie zusätzlich von einem weiteren Interface. Insbesondere weißt die erbende Klasse 9 alle Attribute und Methoden des Interfaces 2 auf. Die Methoden und Attribute der erbenden Klasse sind alle nicht abstrakt.

Wird ein Objekt erzeugt, welches von der erbenden Klasse 9 abgeleitet wird, dann wird für alle abstrakten Mitglieder des Interfaces 2 überprüft ob es jeweils ein nicht abstraktes Mitglied in der erbenden Klasse 9 gibt, welches die gleichen Eigenschaften besitzt. Beispielsweise weist das Interface 2 das Attribut 3 „Attribut“ auf. Auch die erbende Klasse 9 weist ein Attribut 10 mit der Bezeichnung „Attribut“ auf. Daher stimmt die Eigenschaft Name des Mitglieds überein. Bei beiden Attributen handelt es sich um ein Attribut und nicht um eine Methode. Daher stimmen diese Mitglieder auch bezüglich des Typs überein. Insbesondere wird auch der Datentyp der Attribute 5, 12 verglichen. Beide Attribute sind vom Datentyp String 5, 12. Deshalb stimmt auch diese Eigenschaft überein. Beim Vergleich der Methode 4 „Operation“ des Interfaces 2 mit der Methode 11 „Operation“ der erbenden Klasse 9 kann festgestellt werden, dass sie in der Eigenschaft des Namens übereinstimmen. Beim Vergleich ihrer Übergabeparameter kann festgestellt werden, dass diese den gleichen Namen „Wert“ 6, 13 haben und vom gleichen Datentyp „String“ 7, 14 sind. Der Rückgabewert des Mitglieds „Operation“ des Interfaces 2 ist ein boolescher Datentyp 8 und der Rückgabewert des Mitglieds „Operation“ der erbenden Klasse 9 ist ebenfalls ein boolescher Datentyp 15. Da für alle abstrakten Mitglieder 3, 4 des Interfaces 2 ein nicht abstraktes Mitglied 10, 11 der erbenden Klasse 9 gefunden werden kann, das bezüglich aller verglichenen Eigenschaften übereinstimmt, kann davon ausgegangen werden, dass die erbende Klasse 9 korrekt von dem Interface 2 geerbt hat. Um sicherzustellen, dass die Mitglieder der richtigen erbenden Klasse bezüglich der Mitglieder des richtigen Interfaces verglichen wird, kann ein Zusammenhang zwischen dem Interface 2 und der erbenden Klasse 9 überprüft werden, indem für das zu erzeugende Objekt überprüft wird, ob es sowohl von der erbenden Klasse 9 abgeleitet wurde und als auch von dem Interface 2.

Dieses Verfahren ist besonders vorteilhaft, wenn es vor einer Ausführung eines Hauptteils durchgeführt wird. Insbesondere im Rahmen eines Modultests. Dadurch kann eine Zeit bis ein Fehler erster Art erkannt wird verkürzt werden. Ein Fehler erster Art ist insbesondere wenn nicht alle abstrakten Mitglieder in der erbenden Klasse 9 realisiert werden oder wenn das Mitglied in der erbenden Klasse 9 bezüglich seiner Eigenschaften nicht mit dem abstrakten Mitglied übereinstimmt.

Eine Softwarekomponente „Client“ greift auf das Interface 2 zu, wenn es auf ein Objekt zugreift, dass eine Instanz einer von dem Interface 2 erbenden Klasse ist. Um sicherzustellen, dass das Objekt eine Instanz einer von dem Interface 2 erbenden Klasse 9 ist, wird dies in einem Ausführungsbeispiel überprüft. Dazu kann beispielsweise ein Funktionsdekorator @typechecked verwendet werden.

Um die Zeit bis ein Fehler zweiter Art erkannt wird zu verkürzen, wird in einem Ausführungsbeispiel diese Überprüfung ebenfalls vor dem Ausführen des Hauptteils durchgeführt. Insbesondere wird die Überprüfung in einem Modultest und/oder in einer composition root zu Beginn der Ausführung des Computerprogramms, wenn Konstruktoren aufgerufen werden, durchgeführt. In diesem Ausführungsbeispiel wird es als Fehler zweiter Art bezeichnet, wenn eine Softwarekomponente, insbesondere entsprechend einem Programmcode, über ein Interface auf ein Objekt zugreift, dass nicht zu dem Objekt gehört, insbesondere das Objekt nicht referenziert.

Wird in einem Ausführungsbeispiel ein Fehler erster Art und/oder ein Fehler zweiter Art erkannt, wird eine Fehlermeldung ausgegeben. Gegebenenfalls wird die Ausführung des Hauptteils verhindert. Die Fehlermeldung kann an einen Benutzer ausgegeben werden und/oder einem externen System zur Verfügung gestellt werden. Insbesondere kann das externe System automatisiert den Fehler erster Art und/oder den Fehler zweiter Art beheben. Wird ein Fehler erster Art während der Instanziierung erkannt, wird insbesondere eine Ausnahme (Exception) erzeugt. Ein Beispiel für eine fehlerhafte Realisierung ist: from happy. typing import Abstractclass, abstractmethod, typechecked

# Definition des Interfaces class ITest(AbstractClass):

@abstractmethod

@typechecked def foo(self, value:int) -> str:

©property

@abstractmethod def bar(self) -> float:

# inkorrekte Realisierung

# - foo besitzt nicht den Dekorator @typechecked

# - bar ist kein Property dass CTestlncorrect(ITest): def foo(self, value:int) -> str: def bar(self) -> float:

Beispielsweise wird die inkorrekte Realisierung folgendermaßen instantziiert: ci = CTestlncorrect()

Durch die Instanziierung ausgelöst, wird für diese beispielhafte fehlerhafte Realisierung, folgende Fehlermeldung ausgegeben:

„Conflicting signature for function 'foo' (function(self, value: int) -> str) in class CTestlncorrect while abstract symbols in class ITest is @typechecked function(self, value: int) -> str. Conflicting signature for function 'bar' (function(self) -> float) in class CTestlncorrect while abstract symbols in class ITest is property[get](self) -> float.

TypeError: Can't instantiate abstract class CTestlncorrect with abstract methods bar, foo ci = CTestlncorrectO"

Weiterhin kann das Testen, insbesondere wenn die Programmiersprache Python verwendet wird, folgendermaßen durchgeführt werden: Ein Computerprogrammteil, insbesondere die „happy. typing" Bibliothek, erweitert die "Abstract Base Class" (ABC-Implementierung) um eine Implementierung, die nur dann eine Realisierung von Interfaces akzeptiert, wenn:

- jedes abstrakte Mitglied von der Klasse implementiert wurde,

- der Typ des abstrakten Mitglieds derselbe ist wie in dem Interface,

- die Argumente des abstrakten Mitglieds die gleichen sind wie in dem Interface,

- die Typen der Argumente und der Rückgabetyp des abstrakten Member die gleichen sind wie in dem Interface, und

- die Dekoratoren des abstrakten Members die gleichen sind wie im Interface. Es wird dabei die komplette Signatur des Members, nicht nur der Name, wie es die ursprüngliche ABC-Implementierung tut, überprüft. Allerdings findet so die Prüfung immer noch zur Laufzeit statt, wenn die Klasse das erste Mal instanziiert wird. Um sicherzustellen, dass die Implementierung einer Klasse mit einem Interface übereinstimmt, muss die Klasse instanziiert werden. Daher reicht es aus, einen einfachen Unit-Test zu erstellen, der lediglich eine Instanz der Klasse erzeugt. Wenn der Unit-Test erfolgreich ist, ist die Implementierung der Klasse konsistent mit dem Interface. Die strenge Konsistenzprüfung findet so zur Zeit des Unit-Tests statt, was viel früher als die Laufzeit der Anwendung ist und sehr ähnlich zu einer "Kompilierzeit" normaler, insbesondere kompilierter, Programmiersprachen ist. Jede Funktion/Methode, die eine Referenz auf das Interface zugewiesen bekommt, sollte einen Typ-Hinweis für diese Schnittstelle verwenden und sie sollte den "@typechecked"-Dekorator verwenden, um eine Laufzeitprüfung der Referenz durchzuführen. Wenn die Referenz keine Instanz des Interfaces ist, würde die Prüfung zur Laufzeit fehlschlagen. So können nur Klassen, die das Interface realisieren dem Argument dieser Funktion/Methode zugewiesen werden. Diese Prüfung findet jedoch erst zur Laufzeit statt, was zu spät für eine "kompilierzeitähnliche Prüfung" ist. Dependency Injection ist ein Muster, bei dem Softwarekomponenten nie direkt von anderen Softwarekomponenten abhängen, sondern von Abstraktionen, insbesondere Interfaces. Außerdem werden die Instanzen aller Abhängigkeiten an einer einzigen Stelle in der Anwendung erstellt. Dieser Ort wird als "composition root" genannt. Innerhalb der Composition Root werden die Abhängigkeiten an die Konstruktoren anderer Klassen übergeben, um einen Abhängigkeitsbaum aufzubauen. Wenn eine Instanz nicht zum erwarteten Typen des Interfaces passt, wird die Prüfung des Typs zur Laufzeit des Konstruktors fehlschlagen. Dieser Fehler tritt in der composition root auf, die direkt beim Start der Anwendung durchgeführt wird. Der Fehler ist direkt beim Start sichtbar. Alternativ kann die composition root auch in einem einfachen Unit-Test überprüft werden, indem der Code ohne weitere Prüfungen ausgeführt wird. Durch dieses Testverfahren stehen in Python Interfaces zur Verfügung, die wie in anderen Programmiersprachen verwendet werden können, um die Wiederverwendbarkeit, Wartbarkeit und Stabilität von Anwendungen zu erhöhen.

Beispielsweise kann das, insbesondere getestete, Computerprogramm für Webanwendungen verwendet werden, die Künstliche-Intelligenz-Algorithmen (Kl Algorithmen) enthalten und/oder von Fachbereichen verwendet werden. Insbesondere kann das getestete Computerprogramm in einem Fahrzeug verwendet werden, beispielsweise für Webanwendungen im Fahrzeug.

Weiterhin kann folgendes bei der Durchführung des Verfahrens gelten: Die Art der Implementierung einer Realisierung von einem Interface entspricht einem gängigen Muster aus anderen Programmiersprachen (Ableitung vom Interface) und bedarf keiner speziellen Keywords, welche gegebenenfalls vergessen werden können. Insbesondere eine vollständige Prüfung der Eigenschaften aller abstrakten Attribute statt, so dass keine versehentliche falsche Realisierung eines Attributes stattfinden kann. Beispielsweise geschieht die Prüfung der Realisierung auf Vollständigkeit erst bei der Instanziierung, womit die Klasse nach der Definition noch zur Laufzeit erweitert werden kann, bzw. es kann von ihr noch abgeleitet werden und in der Ableitung wird dann die Vollständigkeit hergestellt. Insbesondere werden Funktionsdekoratoren als Eigenschaften mitberücksichtigt, insbesondere falls diese speziell präpariert wurden, was vor allem beim Dekorator @typechecked für eine Laufzeit-Typprüfung extrem wichtig ist. Zu beachten ist, dass das herkömmliche Konzept von Interfaces und deren Realisierung, in anderen OOP-Sprachen, insbesondere kompilierbare Programmiersprachen, immer zwischen Compilezeit und Ausführungszeit (Laufzeit) unterscheidet. Die Prüfung der Vollständigkeit einer Realisierung geschieht in diesen Programmiersprachen statisch während der Compilezeit. In Python gibt es keine Compilezeit, sondern nur die Ausführungszeit, weswegen die Prüfung zum Zeitpunkt der Instanziierung stattfindet. Dieses Problem kann jedoch durch die konsequente Verwendung des @typechecked Dakorators zusammen mit den hier genannten Interfaces umgangen werden, wenn die Klassen konsequent durch Unit-Tests und Integrations-Tests geprüft werden. In diesem Fall kann man trotz dem Nachteil der Prüfung zur Ausführungszeit anstatt zur Compilezeit eine gleiche Code-Qualität erreichen, da ein Abweichen einer Realisierung vom Interface somit sehr schnell auftritt. Hierzu reicht für jede Realisierung nur ein einziger Testcase aus. Dieser kann beispielsweise folgendermaßen programmiert werden: def test_realization(): instance = Realization() assert isinstance(instance, Interface)

Die erste Prüfung findet implizit statt, wenn die Klasse "Realization" instanziiert wird. Hier wird mit dem beschriebenen Konzept die Realisierung auf Vollständigkeit geprüft. Die zweite Prüfung findet danach statt und prüft, ob die instanziierte Klasse tatsächlich von dem zu erwartenden Interface abgeleitet ist. Wenn jede implementierte Klasse einen solchen Test bekommt, ist sichergestellt, dass jede Realisierung das jeweilige Interface vollständig realisiert. Die Prüfung findet also tatsächlich nicht mehr zur Laufzeit statt (wodurch Fehler erst spät auffallen), sondern bereits zum Zeitpunkt der Unit-Test. Somit erreicht Python hier die gleiche Sicherheit bei der Interface-Programmierung wie sie sonst nur von kompilierbaren OOP-Programmiersprachen bekannt sind.

Bezugszeichenliste

Klassendiagramm abstrakte Klasse, Interface

Klassenmitglied

Klassenmitglied

Datentyp

Übergabeparameter

Datentyp

Datentyp erbende Klasse

Klassenmitglied

Klassenmitglied

Datentyp

Übergabeparameter

Datentyp

Datentyp