Okay, ich bin fertig mit der Suche nach guten Informationen dazu. Ich habe eine Reihe von Komponententests, die eine statische Klasse aufrufen, die nach der Initialisierung Eigenschaften festlegt, die sich nicht ändern können (oder möchten).
Mein Problem ist, dass ich keine festgelegte Reihenfolge für die Ausführung der Tests erzwingen kann. Wenn ich könnte, könnte ich sie so ausführen, dass die statischen Eigenschaften zuverlässig festgelegt würden, und ich könnte sie bestätigen, aber leider führt das Microsoft.VisualStudio.TestTools.UnitTesting-Framework sie nur in einer scheinbar zufälligen Reihenfolge aus .
Also fand ich diese http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.priorityattribute.aspx, die im Abschnitt "Bemerkungen" lautet: "Dieses Attribut wird vom Testsystem nicht verwendet. Es wird dem Benutzer für benutzerdefinierte Zwecke zur Verfügung gestellt. " Huh? Was nützt es dann? Erwarten sie, dass ich meinen eigenen Test-Wrapper schreibe, um dieses fabelhafte Attribut zu nutzen (von dem ich mich leicht selbst schreiben könnte, wenn ich mich so anstrengen wollte ...)?
Also genug von der Schimpfe; Gibt es unter dem Strich eine Möglichkeit, die Reihenfolge zu steuern, in der meine Komponententests ausgeführt werden?
[TestMethod]
[Priority(0)]
usw. scheint NICHT zu funktionieren, was Sinn macht, da Microsoft sagt, dass dies nicht der Fall ist.
Bitte auch keine Kommentare zu "Verletzung der Isolation". Die Testklasse isoliert, was ich teste, nicht die einzelnen Testmethoden. Unabhängig davon kann jeder Test unabhängig und problemlos ausgeführt werden. Sie können nur nicht in zufälliger Reihenfolge zusammen ausgeführt werden, da die statische Klasse nicht heruntergerissen werden kann.
Oh, ich weiß auch über "Ordered Test" Bescheid.
quelle
Antworten:
Führen Sie Ihre Tests zu einem riesigen Test zusammen. Um die Testmethode besser lesbar zu machen, können Sie so etwas tun
[TestMethod] public void MyIntegratonTestLikeUnitTest() { AssertScenarioA(); AssertScenarioB(); .... } private void AssertScenarioA() { // Assert } private void AssertScenarioB() { // Assert }
Tatsächlich schlägt das Problem vor, dass Sie wahrscheinlich die Testbarkeit der Implementierung verbessern sollten.
quelle
Sie können die Wiedergabeliste verwenden
Klicken Sie mit der rechten Maustaste auf die Testmethode -> Zur Wiedergabeliste hinzufügen -> Neue Wiedergabeliste
Die Ausführungsreihenfolge wird so sein, wie Sie sie zur Wiedergabeliste hinzufügen. Wenn Sie sie jedoch ändern möchten, haben Sie die Datei
quelle
Wie Sie inzwischen wissen sollten, sagen Puristen, es sei verboten, geordnete Tests durchzuführen. Dies könnte für Unit-Tests zutreffen. MSTest und andere Unit-Test-Frameworks werden verwendet, um reine Unit-Tests durchzuführen, aber auch UI-Tests, vollständige Integrationstests, wie Sie es nennen. Vielleicht sollten wir sie nicht Unit Test Frameworks nennen, oder vielleicht sollten wir sie entsprechend unseren Bedürfnissen verwenden. Das machen die meisten Leute sowieso.
Ich führe VS2015 aus und MUSS Tests in einer bestimmten Reihenfolge ausführen, da ich UI-Tests (Selenium) ausführe.
Priorität - Tut überhaupt nichts Dieses Attribut wird vom Testsystem nicht verwendet. Es wird dem Benutzer für benutzerdefinierte Zwecke zur Verfügung gestellt.
bestellter Test - es funktioniert, aber ich empfehle es nicht, weil:
Andere Vorschläge in diesem Thread sind interessant, aber Sie verlieren die Möglichkeit, den Testfortschritt im Test Explorer zu verfolgen.
Sie haben die Lösung, von der Purist abraten wird, aber tatsächlich funktioniert die Lösung: Sortieren nach Deklarationsreihenfolge .
Der MSTest-Executor verwendet ein Interop, das es schafft, die Deklarationsreihenfolge abzurufen. Dieser Trick funktioniert so lange, bis Microsoft den Test-Executor-Code ändert.
Dies bedeutet, dass die an erster Stelle deklarierte Testmethode vor der an zweiter Stelle deklarierten ausgeführt wird.
Um Ihnen das Leben zu erleichtern, sollte die Deklarationsreihenfolge mit der alphabetischen Reihenfolge übereinstimmen, die im Test-Explorer angezeigt wird.
Ich empfehle dringend einige alte und getestete Regeln:
SEHR WICHTIG
Um die Tests in der Deklarationsreihenfolge auszuführen, müssen Sie im Test-Explorer Alle ausführen verwenden .
Angenommen, Sie haben 3 Testklassen (in meinem Fall Tests für Chrome, Firefox und Edge). Wenn Sie eine bestimmte Klasse auswählen und mit der rechten Maustaste auf Ausgewählte Tests ausführen klicken , wird normalerweise die zuletzt deklarierte Methode ausgeführt.
Wie ich bereits sagte, sollten die deklarierte Bestellung und die angegebene Bestellung übereinstimmen, da Sie sonst in kürzester Zeit große Probleme haben.
quelle
Ich sehe niemanden, der die
ClassInitialize
Attributmethode erwähnt. Die Attribute sind ziemlich einfach.Erstellen Sie Methoden, die entweder mit dem Attribut
[ClassInitialize()]
oder gekennzeichnet sind[TestInitialize()]
, um Aspekte der Umgebung vorzubereiten, in der Ihr Komponententest ausgeführt wird. Damit soll ein bekannter Status für die Ausführung Ihres Komponententests festgelegt werden. Beispielsweise können Sie[ClassInitialize()]
die[TestInitialize()]
Methode oder verwenden, um bestimmte Datendateien zu kopieren, zu ändern oder zu erstellen, die Ihr Test verwenden wird.Erstellen Sie Methoden, die entweder mit dem Attribut
[ClassCleanup()]
oder gekennzeichnet sind[TestCleanUp{}]
, um die Umgebung nach dem Ausführen eines Tests in einen bekannten Zustand zurückzusetzen. Dies kann das Löschen von Dateien in Ordnern oder die Rückkehr einer Datenbank in einen bekannten Zustand bedeuten. Ein Beispiel hierfür ist das Zurücksetzen einer Inventardatenbank auf einen Anfangszustand nach dem Testen einer Methode, die in einer Auftragserfassungsanwendung verwendet wird.[ClassInitialize()]
VerwendenClassInitialize
Sie diese Option , um Code auszuführen, bevor Sie den ersten Test in der Klasse ausführen.[ClassCleanUp()]
Verwenden SieClassCleanup
diese Option , um Code auszuführen, nachdem alle Tests in einer Klasse ausgeführt wurden.[TestInitialize()]
VerwendenTestInitialize
Sie diese Option , um Code auszuführen, bevor Sie jeden Test ausführen.[TestCleanUp()]
Verwenden SieTestCleanup
diese Option , um Code nach jedem Test auszuführen.quelle
Da Sie bereits die Funktionalität für geordnete Tests erwähnt haben, die das Visual Studio-Testframework bereitstellt, werde ich dies ignorieren. Sie scheinen sich auch bewusst zu sein, dass das, was Sie erreichen möchten, um diese statische Klasse zu testen, eine "schlechte Idee" ist, also werde ich das ignorieren.
Konzentrieren wir uns stattdessen darauf, wie Sie möglicherweise tatsächlich sicherstellen können, dass Ihre Tests in der gewünschten Reihenfolge ausgeführt werden. Eine Option (wie von @gaog bereitgestellt) ist "eine Testmethode, viele Testfunktionen", bei der Ihre Testfunktionen in der gewünschten Reihenfolge innerhalb einer einzelnen mit dem
TestMethod
Attribut gekennzeichneten Funktion aufgerufen werden. Dies ist der einfachste Weg, und der einzige Nachteil besteht darin, dass die erste fehlgeschlagene Testfunktion die Ausführung einer der verbleibenden Testfunktionen verhindert .Mit Ihrer Beschreibung der Situation ist dies die Lösung, die ich Ihnen empfehlen würde.
Wenn der fettgedruckte Teil ein Problem für Sie darstellt, können Sie eine geordnete Ausführung isolierter Tests durchführen, indem Sie die integrierten datengesteuerten Testfunktionen nutzen. Es ist komplizierter und fühlt sich ein bisschen schmutzig an, aber es erledigt den Job.
Kurz gesagt, Sie definieren eine Datenquelle (wie eine CSV-Datei oder eine Datenbanktabelle), die die Reihenfolge steuert, in der Sie Ihre Tests ausführen müssen, sowie die Namen der Funktionen, die die Testfunktionalität tatsächlich enthalten. Anschließend binden Sie diese Datenquelle in einen datengesteuerten Test ein, verwenden die Option für sequentielles Lesen und führen Ihre Funktionen in der gewünschten Reihenfolge als einzelne Tests aus.
[TestClass] public class OrderedTests { public TestContext TestContext { get; set; } private const string _OrderedTestFilename = "TestList.csv"; [TestMethod] [DeploymentItem(_OrderedTestFilename)] [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", _OrderedTestFilename, _OrderedTestFilename, DataAccessMethod.Sequential)] public void OrderedTests() { var methodName = (string)TestContext.DataRow[0]; var method = GetType().GetMethod(methodName); method.Invoke(this, new object[] { }); } public void Method_01() { Assert.IsTrue(true); } public void Method_02() { Assert.IsTrue(false); } public void Method_03() { Assert.IsTrue(true); } }
In meinem Beispiel habe ich eine unterstützende Datei namens TestList.csv, die in die Ausgabe kopiert wird. Es sieht aus wie das:
Ihre Tests werden in der von Ihnen angegebenen Reihenfolge und in normaler Testisolation ausgeführt (dh wenn einer fehlschlägt, wird der Rest weiterhin ausgeführt, wobei jedoch statische Klassen gemeinsam genutzt werden).
Das Obige ist eigentlich nur die Grundidee. Wenn ich es in der Produktion verwenden würde, würde ich die Namen der Testfunktionen und deren Reihenfolge dynamisch generieren, bevor der Test ausgeführt wird. Vielleicht können Sie mithilfe von PriorityAttribute und einem einfachen Reflektionscode die Testmethoden in der Klasse extrahieren und entsprechend sortieren und diese Reihenfolge dann in die Datenquelle schreiben.
quelle
Hier ist eine Klasse, die zum Einrichten und Ausführen geordneter Tests unabhängig vom MS Ordered Tests-Framework verwendet werden kann, z. B. um die Argumente mstest.exe auf einer Build-Maschine nicht anpassen oder geordnete mit nicht geordneten in einer Klasse mischen zu müssen.
Das ursprüngliche Testframework sieht die Liste der geordneten Tests nur als einen einzelnen Test an, sodass Init / Cleanup wie [TestInitalize ()] Init () nur vor und nach dem gesamten Satz aufgerufen wird.
Verwendung:
[TestMethod] // place only on the list--not the individuals public void OrderedStepsTest() { OrderedTest.Run(TestContext, new List<OrderedTest> { new OrderedTest ( T10_Reset_Database, false ), new OrderedTest ( T20_LoginUser1, false ), new OrderedTest ( T30_DoLoginUser1Task1, true ), // continue on failure new OrderedTest ( T40_DoLoginUser1Task2, true ), // continue on failure // ... }); }
Implementierung:
using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace UnitTests.Utility { /// <summary> /// Define and Run a list of ordered tests. /// 2016/08/25: Posted to SO by crokusek /// </summary> public class OrderedTest { /// <summary>Test Method to run</summary> public Action TestMethod { get; private set; } /// <summary>Flag indicating whether testing should continue with the next test if the current one fails</summary> public bool ContinueOnFailure { get; private set; } /// <summary>Any Exception thrown by the test</summary> public Exception ExceptionResult; /// <summary> /// Constructor /// </summary> /// <param name="testMethod"></param> /// <param name="continueOnFailure">True to continue with the next test if this test fails</param> public OrderedTest(Action testMethod, bool continueOnFailure = false) { TestMethod = testMethod; ContinueOnFailure = continueOnFailure; } /// <summary> /// Run the test saving any exception within ExceptionResult /// Throw to the caller only if ContinueOnFailure == false /// </summary> /// <param name="testContextOpt"></param> public void Run() { try { TestMethod(); } catch (Exception ex) { ExceptionResult = ex; throw; } } /// <summary> /// Run a list of OrderedTest's /// </summary> static public void Run(TestContext testContext, List<OrderedTest> tests) { Stopwatch overallStopWatch = new Stopwatch(); overallStopWatch.Start(); List<Exception> exceptions = new List<Exception>(); int testsAttempted = 0; for (int i = 0; i < tests.Count; i++) { OrderedTest test = tests[i]; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); testContext.WriteLine("Starting ordered test step ({0} of {1}) '{2}' at {3}...\n", i + 1, tests.Count, test.TestMethod.Method, DateTime.Now.ToString("G")); try { testsAttempted++; test.Run(); } catch { if (!test.ContinueOnFailure) break; } finally { Exception testEx = test.ExceptionResult; if (testEx != null) // capture any "continue on fail" exception exceptions.Add(testEx); testContext.WriteLine("\n{0} ordered test step {1} of {2} '{3}' in {4} at {5}{6}\n", testEx != null ? "Error: Failed" : "Successfully completed", i + 1, tests.Count, test.TestMethod.Method, stopWatch.ElapsedMilliseconds > 1000 ? (stopWatch.ElapsedMilliseconds * .001) + "s" : stopWatch.ElapsedMilliseconds + "ms", DateTime.Now.ToString("G"), testEx != null ? "\nException: " + testEx.Message + "\nStackTrace: " + testEx.StackTrace + "\nContinueOnFailure: " + test.ContinueOnFailure : ""); } } testContext.WriteLine("Completed running {0} of {1} ordered tests with a total of {2} error(s) at {3} in {4}", testsAttempted, tests.Count, exceptions.Count, DateTime.Now.ToString("G"), overallStopWatch.ElapsedMilliseconds > 1000 ? (overallStopWatch.ElapsedMilliseconds * .001) + "s" : overallStopWatch.ElapsedMilliseconds + "ms"); if (exceptions.Any()) { // Test Explorer prints better msgs with this hierarchy rather than using 1 AggregateException(). throw new Exception(String.Join("; ", exceptions.Select(e => e.Message), new AggregateException(exceptions))); } } } }
quelle
Ich werde die Reihenfolge der Tests leider nicht ansprechen. Andere haben es bereits getan. Wenn Sie über "bestellte Tests" Bescheid wissen, ist dies die Antwort von MS VS auf das Problem. Ich weiß, dass diese bestellten Tests keinen Spaß machen. Aber sie dachten, es wird "es" sein und es gibt wirklich nichts mehr in MSTest.
Ich schreibe über eine Ihrer Annahmen:
Sofern Ihre statische Klasse keinen prozessweiten externen Status außerhalb Ihres Codes darstellt (z. B. den Status einer nicht verwalteten nativen DLL-Bibliothek, die vom Rest Ihres Codes aufgerufen wird), ist Ihre Annahme
there is no way
nicht wahr.Wenn sich Ihre statische Klasse darauf bezieht, dann haben Sie leider vollkommen recht, der Rest dieser Antwort ist irrelevant. Da Sie das nicht gesagt haben, gehe ich davon aus, dass Ihr Code "verwaltet" ist.
Denken Sie nach und überprüfen Sie die
AppDomain
Ding. Es wird selten benötigt, aber genau dies ist der Fall, wenn Sie sie wahrscheinlich verwenden möchten.Sie können eine neue AppDomain erstellen, den Test dort instanziieren und dort die Testmethode ausführen. Statische Daten, die vom verwalteten Code verwendet werden, werden dort isoliert. Nach Abschluss können Sie die AppDomain entladen und alle Daten, einschließlich der statischen Daten, werden verdampft. Dann würde der nächste Test eine andere Appdomain initialisieren und so weiter.
Dies funktioniert nur, wenn Sie einen externen Status haben, den Sie verfolgen müssen. AppDomains isolieren nur den verwalteten Speicher. Jede native DLL wird weiterhin pro Prozess geladen und ihr Status wird von allen AppDomains gemeinsam genutzt.
Außerdem verlangsamt das Erstellen / Herunterfahren der Appdomains die Tests. Möglicherweise haben Sie auch Probleme mit der Assemblyauflösung in der untergeordneten Appdomain, diese können jedoch mit einer angemessenen Menge wiederverwendbaren Codes gelöst werden.
Außerdem können kleine Probleme beim Übergeben von Testdaten an die untergeordnete AppDomain und von dieser zurück auftreten. Übergebene Objekte müssen entweder auf irgendeine Weise serialisierbar sein oder sein
MarshalByRef
oder usw. Das domänenübergreifende Sprechen ist fast wie IPC.Achten Sie hier jedoch darauf, dass das Sprechen zu 100% verwaltet wird. Wenn Sie besonders vorsichtig sind und dem AppDomain-Setup ein wenig Arbeit hinzufügen, können Sie sogar Delegaten übergeben und in der Zieldomäne ausführen. Anstatt einige haarige domänenübergreifende Einstellungen vorzunehmen, können Sie Ihre Tests mit folgenden Elementen abschließen:
void testmethod() { TestAppDomainHelper.Run( () => { // your test code }); }
oder auch
[IsolatedAppDomain] void testmethod() { // your test code }
wenn Ihr Testframework das Erstellen solcher Wrapper / Erweiterungen unterstützt. Nach anfänglichen Forschungen und Arbeiten ist ihre Verwendung fast trivial.
quelle
Ich sehe, dass dieses Thema fast 6 Jahre alt ist und wir jetzt eine neue Version von Visual Studio haben, aber ich werde trotzdem antworten. Ich hatte dieses Ordnungsproblem in Visual Studio 19 und habe es herausgefunden, indem ich vor Ihrem Methodennamen einen Großbuchstaben (Sie können auch einen Kleinbuchstaben hinzufügen) und in alphabetischer Reihenfolge wie folgt hinzugefügt habe:
[TestMethod] public void AName1() {} [TestMethod] public void BName2() {}
Und so weiter. Ich weiß, dass dies nicht ansprechend aussieht, aber es sieht so aus, als würde Visual Ihre Tests im Test Explorer in alphabetischer Reihenfolge sortieren, unabhängig davon, wie Sie sie in Ihren Code schreiben. Die Wiedergabeliste hat in diesem Fall bei mir nicht funktioniert.
Hoffe das wird helfen.
quelle
Sie können Namespaces und Klassen in alphabetischer Reihenfolge benennen. z.B.:
Dabei
MyApp.Test.Stage01_Setup
handelt es sich um einen Namespace undStep01_BuildDB
einen Klassennamen.quelle