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.: