XUnit.net 在运行后立即捕获每个测试的结果
XUnit.net capture the result of each test right after it runs
我正在尝试使用 XUnit.net 来替代自定义的本地测试调度程序。自制调度程序的一个特点是,对于 long-运行ning 的测试,它将测试结果(pass/fail,以及导致失败的异常)输出到一个测试后的数据库 passes/fails.
因为可能有大量的长时间 运行ning 测试,这对于查看 运行 过程中的测试进度很有用(不必等待完整的测试通过直到您看到所有结果,因为完整的测试通过可能需要时间)。
XUnit.net 来源在这里:https://github.com/xunit/xunit
我看过 BeforeAfterTestAttribute,但是 "After" 方法不能访问测试结果,只能访问测试方法。我想要类似的东西,但它也可以访问测试结果,这样我就可以立即向数据库报告结果(而不必等待完整的测试套件完成)。
似乎(从源头上)唯一可以访问实际测试结果的是 TestRunner,但据我所知,测试没有可扩展性模型 运行纳尔。
我想出的一个可能的解决方法如下:
[Fact]
TestMethod()
{
//This method takes a lambda, handles exceptions, uploads to my
//database, and then rethrows.
RunTestWithExtraLogging(() =>
{
//Actual test goes here
}
}
上述解决方案并不理想,因为它需要每个测试的作者调用 "RunTestWithExtraLogging" 方法。
PS:我愿意考虑使用不同的测试框架(xUnit.net 除外),如果它支持这个...
是的,我相信您需要创建自己的跑步者。下面提供了一个关于如何完成此操作的简单示例(您需要在 TestMethodRunnerCallback
方法中添加所需的逻辑:
namespace MyTestRunner
{
using System;
using System.Linq;
using Xunit;
public class Program
{
public static int Main(string[] args)
{
var testAssembly = TestAssemblyBuilder.Build(
new ExecutorWrapper(args[0], null, false));
var tests = testAssembly.EnumerateTestMethods(x => x
.DisplayName
.ToLowerInvariant();
var testMethods = (args.Length > 1 && !string.IsNullOrEmpty(args[1])
? tests.Contains(args[1].ToLowerInvariant())).ToList()
: tests.ToList();
if (testMethods.Count == 0)
return 0;
var runnerCallback = new TestMethodRunnerCallback();
testAssembly.Run(testMethods, runnerCallback);
return runnerCallback.FailedCount;
}
public class TestMethodRunnerCallback : ITestMethodRunnerCallback
{
public int FailedCount { get; private set; }
public void AssemblyFinished(TestAssembly testAssembly, int total, int failed, int skipped, double time)
{
FailedCount = failed;
}
public void AssemblyStart(TestAssembly testAssembly)
{
}
public bool ClassFailed(TestClass testClass, string exceptionType, string message, string stackTrace)
{
return true;
}
public void ExceptionThrown(TestAssembly testAssembly, Exception exception)
{
}
public bool TestFinished(TestMethod testMethod)
{
return true;
}
public bool TestStart(TestMethod testMethod)
{
return true;
}
}
}
}
编辑:
似乎在 xUnit.net 2.0 中 TestAssemblyBuilder
已被 XunitFrontController
取代。下面的代码显示了如何捕获测试通过结果的片段,因为测试是 运行:
public class Program
{
public static void Main(string[] args)
{
string assemblyPath = @"path";
XunitFrontController controller = new XunitFrontController(
assemblyPath);
TestAssemblyConfiguration assemblyConfiguration = new TestAssemblyConfiguration();
ITestFrameworkDiscoveryOptions discoveryOptions = TestFrameworkOptions.ForDiscovery(assemblyConfiguration);
ITestFrameworkExecutionOptions executionOptions = TestFrameworkOptions.ForExecution(assemblyConfiguration);
IMessageSink messageSink = new CustomTestMessageVisitor<ITestMessage>();
Console.WriteLine("Running tests");
controller.RunAll(
messageSink: messageSink,
discoveryOptions: discoveryOptions,
executionOptions: executionOptions);
}
}
public class CustomTestMessageVisitor<T> : TestMessageVisitor<T> where T : ITestMessage
{
protected override bool Visit(ITestFinished message)
{
Console.WriteLine("Test {0} finished.",
message.Test.DisplayName);
return true;
}
protected override bool Visit(ITestPassed message)
{
Console.WriteLine("Test {0} passed", message.Test.DisplayName);
return true;
}
protected override bool Visit(ITestFailed message)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (string exceptionType in message.ExceptionTypes)
{
stringBuilder.AppendFormat("{0}, ", exceptionType);
}
Console.WriteLine("Test {0} failed with {1}",
message.Test.DisplayName,
stringBuilder.ToString());
return true;
}
}
我正在尝试使用 XUnit.net 来替代自定义的本地测试调度程序。自制调度程序的一个特点是,对于 long-运行ning 的测试,它将测试结果(pass/fail,以及导致失败的异常)输出到一个测试后的数据库 passes/fails.
因为可能有大量的长时间 运行ning 测试,这对于查看 运行 过程中的测试进度很有用(不必等待完整的测试通过直到您看到所有结果,因为完整的测试通过可能需要时间)。
XUnit.net 来源在这里:https://github.com/xunit/xunit
我看过 BeforeAfterTestAttribute,但是 "After" 方法不能访问测试结果,只能访问测试方法。我想要类似的东西,但它也可以访问测试结果,这样我就可以立即向数据库报告结果(而不必等待完整的测试套件完成)。
似乎(从源头上)唯一可以访问实际测试结果的是 TestRunner,但据我所知,测试没有可扩展性模型 运行纳尔。
我想出的一个可能的解决方法如下:
[Fact]
TestMethod()
{
//This method takes a lambda, handles exceptions, uploads to my
//database, and then rethrows.
RunTestWithExtraLogging(() =>
{
//Actual test goes here
}
}
上述解决方案并不理想,因为它需要每个测试的作者调用 "RunTestWithExtraLogging" 方法。
PS:我愿意考虑使用不同的测试框架(xUnit.net 除外),如果它支持这个...
是的,我相信您需要创建自己的跑步者。下面提供了一个关于如何完成此操作的简单示例(您需要在 TestMethodRunnerCallback
方法中添加所需的逻辑:
namespace MyTestRunner
{
using System;
using System.Linq;
using Xunit;
public class Program
{
public static int Main(string[] args)
{
var testAssembly = TestAssemblyBuilder.Build(
new ExecutorWrapper(args[0], null, false));
var tests = testAssembly.EnumerateTestMethods(x => x
.DisplayName
.ToLowerInvariant();
var testMethods = (args.Length > 1 && !string.IsNullOrEmpty(args[1])
? tests.Contains(args[1].ToLowerInvariant())).ToList()
: tests.ToList();
if (testMethods.Count == 0)
return 0;
var runnerCallback = new TestMethodRunnerCallback();
testAssembly.Run(testMethods, runnerCallback);
return runnerCallback.FailedCount;
}
public class TestMethodRunnerCallback : ITestMethodRunnerCallback
{
public int FailedCount { get; private set; }
public void AssemblyFinished(TestAssembly testAssembly, int total, int failed, int skipped, double time)
{
FailedCount = failed;
}
public void AssemblyStart(TestAssembly testAssembly)
{
}
public bool ClassFailed(TestClass testClass, string exceptionType, string message, string stackTrace)
{
return true;
}
public void ExceptionThrown(TestAssembly testAssembly, Exception exception)
{
}
public bool TestFinished(TestMethod testMethod)
{
return true;
}
public bool TestStart(TestMethod testMethod)
{
return true;
}
}
}
}
编辑:
似乎在 xUnit.net 2.0 中 TestAssemblyBuilder
已被 XunitFrontController
取代。下面的代码显示了如何捕获测试通过结果的片段,因为测试是 运行:
public class Program
{
public static void Main(string[] args)
{
string assemblyPath = @"path";
XunitFrontController controller = new XunitFrontController(
assemblyPath);
TestAssemblyConfiguration assemblyConfiguration = new TestAssemblyConfiguration();
ITestFrameworkDiscoveryOptions discoveryOptions = TestFrameworkOptions.ForDiscovery(assemblyConfiguration);
ITestFrameworkExecutionOptions executionOptions = TestFrameworkOptions.ForExecution(assemblyConfiguration);
IMessageSink messageSink = new CustomTestMessageVisitor<ITestMessage>();
Console.WriteLine("Running tests");
controller.RunAll(
messageSink: messageSink,
discoveryOptions: discoveryOptions,
executionOptions: executionOptions);
}
}
public class CustomTestMessageVisitor<T> : TestMessageVisitor<T> where T : ITestMessage
{
protected override bool Visit(ITestFinished message)
{
Console.WriteLine("Test {0} finished.",
message.Test.DisplayName);
return true;
}
protected override bool Visit(ITestPassed message)
{
Console.WriteLine("Test {0} passed", message.Test.DisplayName);
return true;
}
protected override bool Visit(ITestFailed message)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (string exceptionType in message.ExceptionTypes)
{
stringBuilder.AppendFormat("{0}, ", exceptionType);
}
Console.WriteLine("Test {0} failed with {1}",
message.Test.DisplayName,
stringBuilder.ToString());
return true;
}
}