Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
xUnit, wie TrxLogger benutzen bzw. Trx Datei schreiben?
dr4g0n76
myCSharp.de - Experte

Avatar #avatar-1768.jpg


Dabei seit:
Beiträge: 2.908
Herkunft: Deutschland

Themenstarter:

xUnit, wie TrxLogger benutzen bzw. Trx Datei schreiben?

beantworten | zitieren | melden

Hallo Kollegen.

Ich hab hier einen Assembly Test Runner, der den Mechanismus von xUnit benutzt (falls ihn jemand benutzen möchte). Es ist auch unbedingt gewünscht, dass wir diesen selber beeinflussen können.
Soweit so gut. (Die Tests sind in einer eigenen Assembly und können durch Angabe des Filenamens der Assembly ausgeführt werden.

Nur, wenn ich den jetzt ausführe, wird ja nicht einfach standardmässig ein *.trx File geschrieben.

Wenn ich aber

dotnet test --logger trx --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput=.\coverage\ Codan.Argus.AcceptanceTests

ausführe, dann schon. Vorausgesetzt die richtigen NuGet packages wurden zur TestAssembly hinzugefügt.

(Danach wird dann der Coverage Report mit

reportgenerator "-reports:C:\Code\TestEnvironment\Codan.Argus.AcceptanceTests\coverage\coverage.opencover.xml" "-targetdir:.\coverage"
erzeugt)

Nur, wenn ich diesen Befehl benutze, ist zwar alles gut bis auf eine Sache:
Die Tests werden ja dann nochmal ausgeführt, einmal durch meinen eigenen TestRunner und einmal eben durch die Kommandozeile.

Wie bekomme ich also den Mechanismus genutzt, von dotnet test -logger trx?

Oder muss ich dann quasi "von Hand" einen trx Logger für jeden Test der ausgeführt wird selbst aufrufen?

EDIT: Wenn ich selber vorher eine Lösung finde, poste ich sie natürlich hier.


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit.Runners;

namespace Codan.Argus.TestEnvironment
{
    public class ExtendedAssemblyRunner : IDisposable
    {
        private AssemblyRunner _assemblyRunner = null;
        
        public delegate void DiscoveryCompleteEventHandler(object sender, DiscoveryCompleteInfo e);
        public event DiscoveryCompleteEventHandler DiscoveryCompleteEvent;

        public delegate void ExecutionCompleteEventHandler(object sender, ExecutionCompleteInfo e);
        public event ExecutionCompleteEventHandler ExecutionCompleteEvent;

        public delegate void TestStartingEventHandler(object sender, TestStartingInfo e);
        public event TestStartingEventHandler TestStartingEvent;

        public delegate void TestSkippedEventHandler(object sender, TestSkippedInfo e);
        public event TestSkippedEventHandler TestSkippedEvent;

        public delegate void TestFailedEventHandler(object sender, TestFailedInfo e);
        public event TestFailedEventHandler TestFailedEvent;

        //public delegate void 

        static object consoleLock = new object();
        private static ManualResetEvent finished = new ManualResetEvent(false);
        private string _testAssembly = null;

        private ExecutionCompleteData _executionCompleteData = null;

        public ExtendedAssemblyRunner(string testAssembly)
        {
            _testAssembly = testAssembly;

            _assemblyRunner = AssemblyRunner.WithAppDomain(testAssembly);
        }

        public ExecutionCompleteData ExecutionCompleteData 
        {
            get { return _executionCompleteData; }
        }
        
        private void WithAppDomain(string testAssembly)
        {
           _assemblyRunner = AssemblyRunner.WithAppDomain(testAssembly);
        }

        public void Start(string testAssembly = null)
        {
            if (testAssembly == null) testAssembly = _testAssembly;

            _assemblyRunner.OnDiscoveryComplete = OnDiscoveryCompleteEvent;
            _assemblyRunner.OnExecutionComplete = OnExecutionCompleteEvent;
            _assemblyRunner.OnTestFailed = OnTestFailedEvent;
            _assemblyRunner.OnTestSkipped = OnTestSkippedEvent;
            _assemblyRunner.OnTestStarting = OnTestStartingEvent;

            _assemblyRunner.Start(typeName: null);

            finished.WaitOne();
            finished.Dispose();
        }

        public AssemblyRunnerStatus Status
        {
            get { return _assemblyRunner.Status; }
        }

        protected void OnDiscoveryCompleteEvent(DiscoveryCompleteInfo info)
        {
            lock (consoleLock)
            {
                if (DiscoveryCompleteEvent != null)
                {
                    DiscoveryCompleteEvent(this, info);
                }

#if DEBUG
                Debug.WriteLine("Discovering...");
#endif
            }
        }


        protected void OnExecutionCompleteEvent(ExecutionCompleteInfo info)
        {
            lock (consoleLock)
            {
                if (ExecutionCompleteEvent != null)
                {
                    ExecutionCompleteEvent(this, info);
                }
#if DEBUG
                Debug.WriteLine(
                    $"Finished: {info.TotalTests} tests in {Math.Round(info.ExecutionTime, 3)}s ({info.TestsFailed} failed, {info.TestsSkipped} skipped)");
#endif
                finished.Set();
            }
        }

        protected void OnTestFailedEvent(TestFailedInfo info)
        {
            lock (consoleLock)
            {
                if (this.TestFailedEvent != null)
                {
                    TestFailedEvent(this, info);
                }

#if DEBUG
                Console.ForegroundColor = ConsoleColor.Red;
                Debug.WriteLine("[FAIL] {0}: {1}", info.TestDisplayName, info.ExceptionMessage);
                if (info.ExceptionStackTrace != null)
                {
                    Debug.WriteLine(info.ExceptionStackTrace);
                }

                Console.ResetColor();
#endif
            }
        }

        protected void OnTestStartingEvent(TestStartingInfo info)
        {
            lock (consoleLock)
            {
                if (this.TestStartingEvent != null)
                {
                    TestStartingEvent(this, info);
                }
#if DEBUG
                Console.ForegroundColor = ConsoleColor.Yellow;
                Debug.WriteLine("[TESTSTARTING] {0}: {1}", info.TestDisplayName, info.MethodName);
                Console.ResetColor();
#endif
            }
        }

        protected void OnTestSkippedEvent(TestSkippedInfo info)
        {
            lock (consoleLock)
            {
                if (this.TestSkippedEvent != null)
                {
                    TestSkippedEvent(this, info);
                }
#if DEBUG
                Console.ForegroundColor = ConsoleColor.Yellow;
                Debug.WriteLine("[SKIP] {0}: {1}", info.TestDisplayName, info.SkipReason);
                Console.ResetColor();
#endif
            }
        }

        public void Dispose()
        {
            _assemblyRunner.Dispose();
            _assemblyRunner = null;
        }
    }
}

P:S.:
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von dr4g0n76 am .
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.826

beantworten | zitieren | melden

Magst Du mal kurz erklären, was das Ziel des ganzen Vorhabens ist, was die Test Runtime so heute nicht unterstützt?
private Nachricht | Beiträge des Benutzers
dr4g0n76
myCSharp.de - Experte

Avatar #avatar-1768.jpg


Dabei seit:
Beiträge: 2.908
Herkunft: Deutschland

Themenstarter:

beantworten | zitieren | melden

Es wurde gewünscht, dass wir einen eigenen TestRunner haben.
Der soll die Tests ausführen.
Basierend auf XUnit.
Das funktioniert.
Die Tests liegen in einer anderen Assembly.

Das gewünschte Verhalten wäre, dass die trx (Test Results) Datei geschrieben wird,
während der TestRunner ausgeführt wird, was ja natürlich hier nicht im Code vorhanden ist.

Jetzt wäre die Frage, ob von
https://www.nuget.org/packages/Microsoft.TestPlatform.Extensions.TrxLogger/
z.B. der Logger irgendwie benutzt werden kann, um die trx Datei zu schreiben?

Aber anscheinend kann xUnit - soweit ich recherchiert habe - aber nicht auf die Events von diesem zugreifen.

Das heisst:

Wenn ich wüsste, dass das so nicht geht (xUnit + Microsoft Object Model + Extensions TrxLogger)
müsste ich einen eigenen Mechanismus implementieren.

Denn sonst würden ja einmal die Tests ausgeführt.

Und dann in der Kommandozeile mit

dotnet test --logger trx --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput=.\coverage\ Codan.Argus.AcceptanceTests

Würden die Tests noch einmal ausfgeführt. (hier sorgt der Zusatz --logger trx dafür, dass die trx Datei geschrieben wird.

Vielleicht ist es jetzt klarer? :-)
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.826

beantworten | zitieren | melden

Wollt ihr einen eigenen TestRunner, damit ihr einen eigenen TestRunner habt, oder steckt dahinter wirklich auch eine Anforderung, die mit den aktuellen Runner(n) nicht abgedeckt ist?
Weil viel lässt sich ja prinzipiell auch durch ordentliche Tests und Co konfigurieren, sodass ein eigener Test Runner nur selten wirklich gebraucht wird.

Dass eine TRX Datei während dem Testen bereits geschrieben wird; ungewöhnlich.
I.d.R. wird diese Datei erst am Ende geschrieben - es kann ja prinzipiell Race Conditions geben.
Je nachdem welche Umgebung Du hast, gibt es CI Plattformen, die auf das Erstellen von TRX "hören" und welche bei denen man das TRX Result aktiv publishen muss.
Bei ersterem könnte es also die Race Condition geben, dass die Testsresultate aufgenommen werden, obwohl die Tests gar nicht fertig sind.

Ich hoffe, dass ihr euch das gut überlegt habt :-)
private Nachricht | Beiträge des Benutzers