.NET-Anwendungen effizient testen

29.09.2005
Von Steve Mostello 
Wie Entwickler ihren .NET-Programmen Beine machen können.

Die Infrastruktur von .NET-Software ist Fluch und Segen zugleich. Zwar eröffnet sie mehr Möglichkeiten für den Aufbau weitverteilter Anwendungen, macht aber dadurch die Suche nach Fehlern zeitraubend und schwierig. Mit dem verbreiteten Einsatz von Web-Services in .NET-Lösungen entsteht ferner eine größere Abhängigkeit zwischen den Anwendungen, woraus sich weitere Probleme ergeben. So ist zusätzliches Wissen über die Konfiguration nötig, um Web-Services-Anwendungen richtig überprüfen zu können. Tester und das Qualitätssicherungsteam sollten in jedem Fall zusammenarbeiten. Diesen Ansatz favorisieren heute bereits viele Organisationen, da er den Beteiligten hilft, eine Anwendung und die an sie gestellten Anforderungen besser zu verstehen. Dies führt zu akkurateren Testplänen und effizienteren Testverfahren, die letztlich die Qualität der Software verbessern helfen.

Was tun bei Konfigurationsproblemen?

Problem: Unzureichende Berechtigungen zum Zugriff auf eine Ressource.

Frage: Ist die Anwendung berechtigt, in Anwendungsverzeichnisse zu schreiben?

Hilfe: Alle Zugriffe und Zugriffsversuche der Anwendung auf die Ressourcen des Computers überprüfen.

Problem: Inkompatible Komponenten (falsche Versionen von Assemblies oder COM/COM+- Objekten).

Hilfe: Lokalisierung durch Aufzeichnung der Interaktionen der Anwendung mit selbst erstellten Komponenten und Komponenten von Drittanbietern, um fehlgeschlagene Aufrufe zu identifizieren.

Problem: Falsche Anwendungseinstellungen in einer .NET-Konfigurationsdatei.

Hilfe: Alle Zugriffe auf die Konfigurationsdateien der Anwendung aufzeichnen, um die Anwendungseinstellungen zurückverfolgen zu können und deren Auswirkungen auf die Ausführung zu verstehen. Ferner sollten die Aufzeichnungen der Anwendungskonfigurationen zweier Computer miteinander verglichen werden, um Unterschiede ausfindig zu machen.

Problem: Konflikte mit anderen Anwendungen und/oder Web-Services.

Hilfe: Alle Interaktionen der Anwendung des Nutzers mit externen Ressourcen oder Diensten erfassen und es dem Nutzer so erlauben, die Zugangsschwierigkeiten schnell zu lokalisieren. Die Aufzeichnung sollte fehlgeschlagene Aufrufe von Web-Services oder.NET Remoting und Fehler beim Zugriff auf Datenbanken umfassen.

Probleme mit .NET-Programmen

Suchen Sie in den Aufzeichnungen des Testdurchlaufs nach den folgenden, häufig auftretenden Problemen:

• Ineffizienter Code:

m Gibt es häufig Ausnahmen?

m Viele große Objekte?

m Ineffiziente Datenbankaufrufe?

• Unsachgemäße Anwendungseinstellungen, einschließlich unzureichender Session-State-Lieferanten oder abgeschalteter Puffer auf einer Web Forms-Seite.

• Interoperabilität mit bestehendem Windows Code:

m Werden große Datenmengen von COM/COM+ an verwaltete .NET-Anwendungen verschoben?

• Infrastrukturprobleme wie:

m Schlechte Reaktionszeiten des Netzes;

m unzureichende Hardware.

Probleme mit Web-Services

Problem: Ineffizienter Betrieb, da die Anwendung bei jeder Anfrage eine Verbindung zur Datenbank öffnet, SQL-Statements oder Stored Procedures schlecht funktionieren.

Hilfe: Lokalisieren Sie dieses Problem durch Aufzeichnen des gesamten Testablaufes auf der Systemebene. Dies verschafft Informationen beispielsweise über den prozentualen Zeitanteil, der auf Garbage Collection verwendet wird, und die Zahl der zugewiesenen Bytes pro Sekunde.

Problem: Speicherverbrauch.

Hilfe: Identifikation durch Leistungsanzeigen (Performance Counter), die darauf hinweisen können, ob die Ursache der Speicher ist. In Frage kommen zum Beispiel der prozentuale Zeitanteil, der auf Garbage Collection verwendet wird, sowie die zugewiesene Bytes pro Sekunde.

Problem: Falsche Einstellungen der Anwendungs- und Umgebungsparameter wie eine unzureichende Höchstzahl von Threads im Thread Pool.

Hilfe: Aufzeichnen aller nötigen Leistungsdaten und Nachrichten im Event Log sowie der Para-meter von Anwendungs- und Bezugssystem (.NET -Konfigurationszugriffe, IIS-Konfiguration und Browser-Einstellungen). Diese Daten weisen dann auf nicht optimierte Einstellungen hin, die für den Geschwindigkeitsverlust der Anwendung verantwortlich waren.

Problem: Ineffiziente Nutzung von Remoting, zum Beispiel durch die Übertragung zu großer Datenmengen bei den einzelnen Remoting-Aufrufen.

Hilfe: Identifikation durch Aufzeichnung aller Remoting-Aufrufe sowohl auf der Client- als auf der Server-Seite.

Nützliche Infos

Weiteren Aufschluss über die .NET-Anwendung und mögliche Probleme geben:

• Die eindeutige Session-ID des Besuchers, Uhrzeit und Datum des Eintreffens der Anfrage auf dem Server, Typ und Statuscode der HTTP-Anfrage. Sie zeigt, wie der Server auf den Client reagiert.

• Vom ASP.NET erzeugte Trace-Informationen darüber, welche Teile des Codes ausgeführt wurden.

• Angaben über in der Page-ID verwendete Steuerelemente, Typ, Wiedergabegröße und Anzeigestatus.

• Vom Client bei der Server-Anfrage versandte Cookies.

• Werte der vom Client an den Server versandten HTTP-Kopfzeilen in einer Name/Wert-Paarung. Diese zeigen den genutzten Browser und das Betriebssystem an.

• Name und Wert von Server-Variablen.

Hier lesen Sie …

• wo Probleme beim Testen von .NET-Anwendungen lauern können,

• welche typischen Leistungsmängel bei .NET auftreten;

• wie Anwendungen konfiguriert werden müssen;

• wie sich Fehler in einer .NET-Anwendung finden lassen.

Tester und Qualitätssicherer sollten zudem eng mit den Entwicklern kooperieren oder sich zumindest mit diesen und dem Auftraggeber regelmäßig besprechen, um mehr Details über die Anwendung zu erfahren. Dabei dürfen Fragen nach dem erwarteten Nutzerverhalten einschließlich des Logins und der benötigten Kapazitäten nicht fehlen, ebenso wie möglichst viele technische Einzelheiten in Erfahrung gebracht werden sollten. Logischerweise wird man in der Entwicklung eher technische Beschreibungen der Anwendung erhalten, während der Auftraggeber mehr über den funktionellen Nutzen, den er erwartet, sprechen wird. Alle Informationen zusammen bilden die Basis eines tragfähigen Testplans. Seine Umsetzung umfasst Funktions- und Belastungstests mit Test-Skripts, die auf gut definierten Nutzungsszenarien aufbauen. Ebenso werden die Kapazitäten und der Durchsatz der Anwendung getestet sowie ihre Login-Funktionen, und Hardware- und Softwareprofile erstellt.

Tauchen nun bei der Überprüfung Performance-Probleme auf, muss der Tester den Entwicklern mitteilen, wo genau die Anwendung abstürzte und was die Ursache war. Um dies in der dezentral organisierten Welt von .NET zu tun, ist Hilfe durch eine ganze Reihe von Mitarbeitern nötig: So muss das Team während der Belastungstests den Datenbankadministrator, den Netzwerkadministrator und einen Entwicklungstechniker hinzuziehen, um verschiedene Teile des Systems zu beobachten. Damit ist nur der erste Schritt getan. Als nächstes gilt es, die Daten, die an den verschiedenen Teilen des Systems generiert wurden, auf Fehler zu durchsuchen, um das Problem und seinen Ursprung zu finden. Dies ist zeitaufwändig.

Alternativ lassen sich Lasttests von Anfang an auf mehreren Anwendungsschichten und an verschiedenen Orten aufzeichnen. Hierzu sind vor allem Testwerkzeuge nötig, die auf Systemebene einen Überblick über alle Geschehnisse geben, die eintreten, wenn die Anwendung unter Belastung läuft. Es geht also darum, alle Log-Daten der Testdurchläufe zu erfassen und so ein vollständiges Bild von den Abläufen in den Anwendungen auf allen Ebenen (Tiers) der Umgebung auf einer synchronisierten Zeitachse zu erhalten. Die Mitarbeit anderer Abteilungen bei der Fehlersuche entfällt, und Entwickler erhalten die benötigten Informationen von dem Tool. Allerdings fallen bei der Datenaufzeichnung große Informationsmengen an, die es nun zu analysieren gilt. Dies können aber nur Tester leisten, die über typische .NET-Probleme gut Bescheid wissen.

Da .NET-Anwendungen sehr dezentral angelegt sind und Web-Services nutzen, sind traditionelle Funktions- und Belastungstests komplexer. Sind Anwendungen nach .NET zu migrieren, können beispielsweise neue Datentypen, Funktionsnamen und nicht mehr verwendete Kennworte Ärger machen. Außerdem kommt dem Kompatibilitätstest des Browsers große Bedeutung zu, da ASP.NET einen HTML-Ouput erzeugt, der genau auf diesen und das Betriebssystem des Anwenders zugeschnitten ist. Bei der Auswertung der Daten sollte der Tester ferner auf häufige Fehlerquellen achten: ineffizienter Code, unsachgemäße Einstellungen in der Anwendung, eine mangelhafte Interoperabilität mit vorhandenem Legacy-Windows-Code oder Netzwerkprobleme.

Macht beispielsweise der Code Schwierigkeiten, könnten zu viele Ausnahmen (Exceptions) ausgelöst worden sein, zu viele große Objekte existieren oder die Datenbankaufrufe mangelhaft sein. Zu den unsachgemäßen Einstellungen in der Anwendung zählen unpassende Session-State-Provider oder abgeschalteter Puffer auf einer Web-Forms-Seite. Geht es um die Interoperabilität mit bestehendem Windows-Code, ist zu fragen, ob COM/COM+-Lösungen große Datenmengen an verwaltete (managed) .NET-Anwendungen verschieben (Marshalling). Die Ursache für Infrastrukturprobleme schließlich können von schlechten Reaktionszeiten des Netzes herrühren oder auf unzureichende Hardwareausstattung, begrenzte Prozessorleistung, Speichermangel etc. zurückzuführen sein.

Effizienz verbessern

Ebenso können Web-Services in einer .NET-Anwendung eine Reihe von Problemen verursachen. So ist möglicherweise der Betrieb ineffizient, weil die Anwendung bei jeder Anfrage eine Verbindung zur Datenbank herstellt oder die SQL-Statements und Stored Procedures nicht performant sind. Tester sollten dann versuchen, den gesamten Testablauf auf Systemebene aufzuzeichnen, um Zahl und Dauer von Funktionsaufrufen zu erfassen. Einem zu hohen Speicherverbrauch kann durch die Aufzeichnungen von Leistungsanzeigen (Performance Counter) auf die Schliche gekommen werden. Dabei werden beispielsweise der prozentuale Zeitanteil, der auf Garbage Collection verwendet wird, und die Zahl der zugewiesenen Bytes pro Sekunde registriert.

Ein weiteres Problem können unterdimensionierte Anwendungs- und Umgebungsparameter sein, beispielsweise durch eine unzureichende Höchstzahl von Threads im Thread Pool. Diesem lässt sich begegnen, indem der Tester die Leistungsanzeigen und Nachrichten im Event Log aufzeichnet sowie die Einstellungen von Anwendung und Framework anschaut (.NET-Konfigurationszugriffe, IIS-Konfiguration und Browser-Einstellungen). Diese Daten weisen dann auf nicht optimierte Einstellungen hin, die für den Geschwindigkeitsverlust der Anwendung verantwortlich waren. Ist schließlich das Remoting ein Problem, etwa weil zu große Datenmengen bei den einzelnen Remoting-Aufrufen übertragen werden, so müssen im Testdurchlauf alle Remoting-Aufrufe sowohl auf der Client- als auch auf der Server-Seite im Tool erfasst werden.

Wenn die Konfiguration hakt

Test- und Qualitätssicherungsteams müssen die Konfigurationsinfrastruktur von .NET zumindest in ihren Grundzügen verstehen. Sie sollten sich dazu von den Entwicklern eine detaillierte Beschreibung der Infrastruktur der Anwendung geben lassen. Diese Informationen helfen, unzureichende Berechtigungen zum Ressourcenzugriff, falsche Anwendungseinstellungen in einer .NET-Konfigurationsdatei oder Konflikte mit anderen Anwendungen erkennen und behandeln zu können. Will der Tester etwa wissen, ob die Anwendung berechtigt ist, in ein Anwendungsverzeichnis zu schreiben, muss er alle Zugriffe und Zugriffsversuche der Anwendung auf die Ressourcen des Computers kontrollieren. Probleme mit inkompatiblen Komponenten (falsche Versionen von Assemblies oder COM/COM+-Objekten) lassen sich angehen, indem die Interaktionen der Anwendung mit selbst erstellten Komponenten und solchen von Drittanbietern lokalisiert werden. Dies hilft, fehlgeschlagene Aufrufe zu identifizieren.

Finden sich falsche Anwendungseinstellungen in einer .NET-Konfigurationsdatei, sind im Test die Zugriffe auf die Konfigurationsdateien der Anwendung aufzuzeichnen. Dadurch lassen sich deren Auswirkungen auf die Ausführung verstehen. Unterschiede finden sich eventuell auch dadurch, dass der Tester die auf zwei Computern gespeicherten Anwendungskonfigurationen miteinander vergleicht. Bei Konflikten zwischen der .NET-Lösung und anderen Anwendungen und/oder Web-Services sollte er alle Interaktionen der Anwendung des Nutzers mit externen Ressourcen oder Diensten aufzeichnen. Dabei sollten auch fehlgeschlagene Aufrufe von Web-Services oder .NET Remoting sowie Fehler beim Zugriff auf Datenbanken erfasst werden.

Finden sich schließlich funktionale Probleme in der Geschäftslogik, hilft es, sämtliche verwalteten und nicht verwalteten Komponenten der Anwendung zu erfassen sowie die Aufrufe öffentlicher Methoden aufzuzeichnen. Finden sich Ausnahmen, könnte das auf Codeprobleme hindeuten. Bleibt die Anwendung hängen oder antwortet nicht (Zeitüberschreitung), sind mehrere Threads und Prozesse auf Systemebene zu erfassen. Bricht die Anwendung regelrecht zusammen, müssen auf Systemebene die Anwendungsausführung und die Ereignisse beim Absturz automatisch festgehalten werden. (as)