MSTest 4.4 ermöglicht die Ausführung von Testprojekten mit demselben Bereitstellungsmodell, auf das die Anwendung in der Produktion möglicherweise setzt, indem Testquellcode generiert und Native AOT sowie Trimming aktiviert werden. Die Idee besteht nicht darin, die übliche Ausführung verwalteter Tests zu ersetzen, sondern einen nativen Pfad hinzuzufügen, der Probleme im Zusammenhang mit der Vorkompilierung und dem Entfernen nicht verwendeten Codes aufdeckt, bevor die Anwendung ausgeliefert wird.
Laut Amaury Levé, Principal Software Engineer, aktiviert die Verwendung von MSTest.Sdk/4.4.0 mit dem Ziel-Framework net10.0 und der Einstellung PublishAot=true die MSTest-Quellcodegenerierung und den Pfad zur nativen ausführbaren Datei. MSTest.Sdk verwendet standardmäßig die Microsoft Testing Platform, kurz MTP. Projekte, die weiterhin VSTest verwenden, sollten die Migrationsanleitung zu MTP prüfen, da sich Befehlszeilenargumente, die CI-Integration und einige unterstützte .runsettings-Einträge unterscheiden.
Was ändert sich in der Praxis?
Nach der Konfiguration des Projekts sollten die Tests für dasselbe Betriebssystem und dieselbe Architektur veröffentlicht werden, auf die die Anwendung abzielt. Die Quelle führt als Beispiel den Bezeichner linux-x64 an; dieser kann durch Werte wie win-x64 oder osx-arm64 ersetzt werden. Nach der Veröffentlichung wird die erzeugte ausführbare Datei direkt ausgeführt oder unter Windows mit der Erweiterung .exe.
Dieser Pfad verringert die Abhängigkeit von einer umfassenden reflektionsbasierten Untersuchung der Assembly, etwa durch den Aufruf von Assembly.GetTypes(), und verwendet generierte Attribute und Delegates, um unterstützte Tests zu erstellen und aufzurufen. Die Quellcodegenerierung bedeutet jedoch nicht, dass Reflection vollständig entfällt; der standardmäßige Modus ReflectionFree behält einige reflektionsbasierte Fallback-Pfade bei. Bei der Untersuchung von Kompatibilitätsproblemen kann MSTestSourceGenMode=Rooting verwendet werden, um erkannte Testmember beizubehalten und gleichzeitig die reflektionsbasierte Ausführung fortzusetzen.
Ein begrenzter CI-Pfad vor der Ausweitung
Die praktische Empfehlung lautet, die schnelle Ausführung verwalteter Tests für das tägliche Feedback beizubehalten und anschließend ein Testprojekt auszuwählen, das unmittelbar für den Bereitstellungspfad relevant ist, um in CI einen Native-AOT-Versuch hinzuzufügen. Die beiden Pfade sollten in drei klaren Punkten verglichen werden:
- Es wird exakt dieselbe Anzahl von Tests entdeckt.
- Die Tests liefern dieselben Ergebnisse.
- Die Zeit für die Veröffentlichung und die native Ausführung wird getrennt von der Zeit für die Testausführung erfasst.
Vorzugsweise sollte der Versuch in einem geplanten Job oder in einer Phase der Release-Validierung beginnen und erst dann auf jeden Pull Request ausgeweitet werden, wenn das dadurch gewonnene Signal die zusätzlichen Kosten für Veröffentlichung und Ausführung rechtfertigt. Außerdem sollte ein Projekt ausgewählt werden, das für die Bereitstellung kritische Pfade testet, etwa Serialisierung, Dependency Injection, Konfigurationsbindung, Reflection-basierte Erweiterungen oder eine Bibliothek, deren Native-AOT-Kompatibilität nachgewiesen werden muss. Ein Projekt, das ausschließlich einfache Berechnungstests enthält, liefert dagegen kaum Belege für die tatsächliche Bereitschaft der Anwendung.
Einschränkungen, die in Abnahmeschranken umgewandelt werden sollten
Ein Teil der Tests kann erfolgreich sein und der Prozess kann erfolgreich beendet werden, obwohl einige Klassen nicht registriert wurden. Dies geschieht beispielsweise, wenn eine Testklasse das Attribut [TestClass] nur erbt, statt es direkt zu deklarieren, oder wenn die Klasse nicht zugänglich, dateilokal, statisch, öffentlich oder abstrakt ist. Die Quelle weist darauf hin, dass die Diagnose MSTEST0069 dabei hilft, einen dieser Fälle aufzudecken. Daher sollte die Übereinstimmung der Testanzahl eine Release-Bedingung und keine ignorierbare Anmerkung sein.
Zu den weiteren Einschränkungen gehören öffentliche Testmethoden oder Methoden, die Parameter mit ref, out oder in verwenden, sowie die fehlende Unterstützung einiger Muster für statische Fixtures über [AssemblyFixtureProvider]. Außerdem sind einige Integrationen des MSTest SDK, MTP-Erweiterungen und CI-Berichte im Native-AOT-Pfad nicht verfügbar, während TRX und Code Coverage dem Artikel zufolge weiterhin unterstützt werden. Deshalb sollten Analyzerwarnungen und Builddiagnosen als Übergangsschranken behandelt werden und nicht als Warnungen, die stummgeschaltet werden.
Warum ist dieser Ansatz wichtig?
Verwaltete Tests und der Native-AOT-Pfad beantworten zwei unterschiedliche Fragen: Der erste beschleunigt den Entwicklungszyklus, der zweite überprüft, ob die Tests selbst innerhalb des Bereitstellungsmodells ausgeführt werden können, das die Anwendung verwenden wird. Dies entspricht keinem umfassenden Test des endgültigen Produktionsartefakts; Konfigurationen, Betriebssystem, Architektur, externe Dienste und Paketierung können abweichen. Der Ansatz beseitigt jedoch eine wichtige Variable: den Unterschied zwischen dem Trimming- und Vorkompilierungsmodell von Test und Anwendung.
Eine Leistungssteigerung ist nicht garantiert und sollte nicht die wichtigste Begründung sein. Die Zeit für Erkennung und Start kann sich durch die Quellcodegenerierung verringern, doch Ausführungszeit, Prozessstart, Veröffentlichung und die verbleibende Reflection können die Gesamtdauer bestimmen. Die redaktionelle Schlussfolgerung lautet daher, dass der Hauptwert des Versuchs in der höheren Übereinstimmung von Test und Bereitstellung liegt, selbst wenn der Geschwindigkeitsgewinn begrenzt ist. Der Ansatz bleibt außerdem reversibel: Wenn die Kosten des Pfads das dadurch gewonnene Vertrauen übersteigen, kann seine Häufigkeit verringert, das ausgewählte Projekt geändert oder der Versuch beendet werden, ohne die verwaltete Testsuite zu beeinträchtigen.