1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Linq ;
4+ using System . Reflection ;
5+ using System . Threading ;
6+ using System . Threading . Tasks ;
7+ using Xunit . Abstractions ;
8+ using Xunit . Sdk ;
9+
10+ [ assembly: Xunit . TestFramework ( "XunitCustomFramework.CustomTestFramework" , "XunitCustomFramework" ) ]
11+
12+ namespace XunitCustomFramework ;
13+
14+ public class CustomTestFramework : XunitTestFramework
15+ {
16+ public CustomTestFramework ( IMessageSink messageSink )
17+ : base ( messageSink )
18+ {
19+ messageSink . OnMessage ( new DiagnosticMessage ( "Using CustomTestFramework" ) ) ;
20+ }
21+
22+ protected override ITestFrameworkExecutor CreateExecutor ( AssemblyName assemblyName )
23+ => new CustomExecutor ( assemblyName , SourceInformationProvider , DiagnosticMessageSink ) ;
24+
25+ private class CustomExecutor : XunitTestFrameworkExecutor
26+ {
27+ public CustomExecutor ( AssemblyName assemblyName , ISourceInformationProvider sourceInformationProvider , IMessageSink diagnosticMessageSink )
28+ : base ( assemblyName , sourceInformationProvider , diagnosticMessageSink )
29+ {
30+ }
31+
32+ protected override async void RunTestCases ( IEnumerable < IXunitTestCase > testCases , IMessageSink executionMessageSink , ITestFrameworkExecutionOptions executionOptions )
33+ {
34+ using var assemblyRunner = new CustomAssemblyRunner ( TestAssembly , testCases , DiagnosticMessageSink , executionMessageSink , executionOptions ) ;
35+ await assemblyRunner . RunAsync ( ) ;
36+ }
37+ }
38+
39+ private class CustomAssemblyRunner : XunitTestAssemblyRunner
40+ {
41+ public CustomAssemblyRunner ( ITestAssembly testAssembly , IEnumerable < IXunitTestCase > testCases , IMessageSink diagnosticMessageSink , IMessageSink executionMessageSink , ITestFrameworkExecutionOptions executionOptions )
42+ : base ( testAssembly , testCases , diagnosticMessageSink , executionMessageSink , executionOptions )
43+ {
44+ }
45+
46+ protected override Task < RunSummary > RunTestCollectionAsync ( IMessageBus messageBus , ITestCollection testCollection , IEnumerable < IXunitTestCase > testCases , CancellationTokenSource cancellationTokenSource )
47+ => new CustomTestCollectionRunner ( testCollection , testCases , DiagnosticMessageSink , messageBus , TestCaseOrderer , new ExceptionAggregator ( Aggregator ) , cancellationTokenSource ) . RunAsync ( ) ;
48+ }
49+
50+ private class CustomTestCollectionRunner : XunitTestCollectionRunner
51+ {
52+ public CustomTestCollectionRunner ( ITestCollection testCollection , IEnumerable < IXunitTestCase > testCases , IMessageSink diagnosticMessageSink , IMessageBus messageBus , ITestCaseOrderer testCaseOrderer , ExceptionAggregator aggregator , CancellationTokenSource cancellationTokenSource )
53+ : base ( testCollection , testCases , diagnosticMessageSink , messageBus , testCaseOrderer , aggregator , cancellationTokenSource )
54+ {
55+ }
56+
57+ protected override Task < RunSummary > RunTestClassAsync ( ITestClass testClass , IReflectionTypeInfo @class , IEnumerable < IXunitTestCase > testCases )
58+ => new CustomTestClassRunner ( testClass , @class , testCases , DiagnosticMessageSink , MessageBus , TestCaseOrderer , new ExceptionAggregator ( Aggregator ) , CancellationTokenSource , CollectionFixtureMappings )
59+ . RunAsync ( ) ;
60+ }
61+
62+ private class CustomTestClassRunner : XunitTestClassRunner
63+ {
64+ public CustomTestClassRunner ( ITestClass testClass , IReflectionTypeInfo @class , IEnumerable < IXunitTestCase > testCases , IMessageSink diagnosticMessageSink , IMessageBus messageBus , ITestCaseOrderer testCaseOrderer , ExceptionAggregator aggregator , CancellationTokenSource cancellationTokenSource , IDictionary < Type , object > collectionFixtureMappings )
65+ : base ( testClass , @class , testCases , diagnosticMessageSink , messageBus , testCaseOrderer , aggregator , cancellationTokenSource , collectionFixtureMappings )
66+ {
67+ }
68+
69+ protected override Task < RunSummary > RunTestMethodAsync ( ITestMethod testMethod , IReflectionMethodInfo method , IEnumerable < IXunitTestCase > testCases , object [ ] constructorArguments )
70+ => new CustomTestMethodRunner ( testMethod , this . Class , method , testCases , this . DiagnosticMessageSink , this . MessageBus , new ExceptionAggregator ( this . Aggregator ) , this . CancellationTokenSource , constructorArguments )
71+ . RunAsync ( ) ;
72+ }
73+
74+ private class CustomTestMethodRunner : XunitTestMethodRunner
75+ {
76+ private readonly IMessageSink _diagnosticMessageSink ;
77+
78+ public CustomTestMethodRunner ( ITestMethod testMethod , IReflectionTypeInfo @class , IReflectionMethodInfo method , IEnumerable < IXunitTestCase > testCases , IMessageSink diagnosticMessageSink , IMessageBus messageBus , ExceptionAggregator aggregator , CancellationTokenSource cancellationTokenSource , object [ ] constructorArguments )
79+ : base ( testMethod , @class , method , testCases , diagnosticMessageSink , messageBus , aggregator , cancellationTokenSource , constructorArguments )
80+ {
81+ _diagnosticMessageSink = diagnosticMessageSink ;
82+ }
83+
84+ protected override async Task < RunSummary > RunTestCaseAsync ( IXunitTestCase testCase )
85+ {
86+ var parameters = string . Empty ;
87+
88+ if ( testCase . TestMethodArguments != null )
89+ {
90+ parameters = string . Join ( ", " , testCase . TestMethodArguments . Select ( a => a ? . ToString ( ) ?? "null" ) ) ;
91+ }
92+
93+ var test = $ "{ TestMethod . TestClass . Class . Name } .{ TestMethod . Method . Name } ({ parameters } )";
94+
95+ _diagnosticMessageSink . OnMessage ( new DiagnosticMessage ( $ "STARTED: { test } ") ) ;
96+
97+ var deadline = TimeSpan . FromMinutes ( 2 ) ;
98+ using var timer = new Timer (
99+ _ => _diagnosticMessageSink . OnMessage ( new DiagnosticMessage ( $ "WARNING: { test } has been running for more than { deadline . TotalMinutes : N0} minutes") ) ,
100+ null ,
101+ deadline ,
102+ Timeout . InfiniteTimeSpan ) ;
103+
104+ try
105+ {
106+ var result = await base . RunTestCaseAsync ( testCase ) ;
107+
108+ var status = result . Failed > 0
109+ ? "FAILURE"
110+ : ( result . Skipped > 0 ? "SKIPPED" : "SUCCESS" ) ;
111+
112+ _diagnosticMessageSink . OnMessage ( new DiagnosticMessage ( $ "{ status } : { test } ({ result . Time } s)") ) ;
113+
114+ return result ;
115+ }
116+ catch ( Exception ex )
117+ {
118+ _diagnosticMessageSink . OnMessage ( new DiagnosticMessage ( $ "ERROR: { test } ({ ex . Message } )") ) ;
119+ throw ;
120+ }
121+ }
122+ }
123+ }
0 commit comments