1 // ****************************************************************
2 // Copyright 2007, Charlie Poole
3 // This is free software licensed under the NUnit license. You may
4 // obtain a copy of the license at http://nunit.org/?p=license&r=2.4
5 // ****************************************************************
7 //#define RUN_IN_PARALLEL
12 using System
.Collections
;
17 /// AggregatingTestRunner allows running multiple TestRunners
18 /// and combining the results.
20 public abstract class AggregatingTestRunner
: MarshalByRefObject
, TestRunner
, EventListener
22 static int AggregateTestID
= 1000;
24 #region Instance Variables
29 protected int runnerID
;
32 /// The downstream TestRunners
34 protected ArrayList runners
;
37 /// The loaded test suite
39 protected TestNode aggregateTest
;
42 /// The result of the last run
44 private TestResult testResult
;
47 /// The event listener for the currently running test
49 protected EventListener listener
;
51 protected string projectName
;
53 protected TestName testName
;
58 public AggregatingTestRunner() : this( 0 ) { }
59 public AggregatingTestRunner( int runnerID
)
61 this.runnerID
= runnerID
;
62 this.testName
= new TestName();
63 testName
.TestID
= new TestID( AggregateTestID
);
64 testName
.RunnerID
= this.runnerID
;
65 testName
.FullName
= testName
.Name
= "Not Loaded";
73 get { return runnerID; }
76 public virtual bool Running
80 foreach( TestRunner runner
in runners
)
88 public virtual IList AssemblyInfo
92 ArrayList info
= new ArrayList();
93 foreach( TestRunner runner
in runners
)
94 info
.AddRange( runner
.AssemblyInfo
);
99 public virtual ITest Test
103 if ( aggregateTest
== null && runners
!= null )
105 // Count non-null tests, in case we specified a fixture
107 foreach( TestRunner runner
in runners
)
108 if ( runner
.Test
!= null )
111 // Copy non-null tests to an array
113 ITest
[] tests
= new ITest
[count
];
114 foreach( TestRunner runner
in runners
)
115 if ( runner
.Test
!= null )
116 tests
[index
++] = runner
.Test
;
118 // Return master node containing all the tests
119 aggregateTest
= new TestNode( testName
, tests
);
122 return aggregateTest
;
126 public virtual TestResult TestResult
128 get { return testResult; }
132 #region Load and Unload Methods
133 public abstract bool Load(TestPackage package
);
135 public virtual void Unload()
137 foreach( TestRunner runner
in runners
)
139 aggregateTest
= null;
143 #region CountTestCases
144 public virtual int CountTestCases( ITestFilter filter
)
147 foreach( TestRunner runner
in runners
)
148 count
+= runner
.CountTestCases( filter
);
153 #region Methods for Running Tests
154 public virtual TestResult
Run( EventListener listener
)
156 return Run( listener
, TestFilter
.Empty
);
159 public virtual TestResult
Run(EventListener listener
, ITestFilter filter
)
161 // Save active listener for derived classes
162 this.listener
= listener
;
164 ITest
[] tests
= new ITest
[runners
.Count
];
165 for( int index
= 0; index
< runners
.Count
; index
++ )
166 tests
[index
] = ((TestRunner
)runners
[index
]).Test
;
168 this.listener
.RunStarted( this.Test
.TestName
.Name
, this.CountTestCases( filter
) );
170 this.listener
.SuiteStarted( this.Test
.TestName
);
171 long startTime
= DateTime
.Now
.Ticks
;
173 TestSuiteResult result
= new TestSuiteResult( new TestInfo( testName
, tests
), projectName
);
174 result
.RunState
= RunState
.Executed
;
175 foreach( TestRunner runner
in runners
)
176 if ( filter
.Pass( runner
.Test
) )
177 result
.AddResult( runner
.Run( this, filter
) );
179 long stopTime
= DateTime
.Now
.Ticks
;
180 double time
= ((double)(stopTime
- startTime
)) / (double)TimeSpan
.TicksPerSecond
;
183 this.listener
.SuiteFinished( result
);
185 this.listener
.RunFinished( result
);
187 this.testResult
= result
;
192 public virtual void BeginRun( EventListener listener
)
194 BeginRun( listener
, TestFilter
.Empty
);
197 public virtual void BeginRun( EventListener listener
, ITestFilter filter
)
199 // Save active listener for derived classes
200 this.listener
= listener
;
203 this.listener
.RunStarted( this.Test
.Name
, this.CountTestCases( filter
) );
205 foreach( TestRunner runner
in runners
)
206 if ( runner
.Test
!= null )
207 runner
.BeginRun( this, filter
);
209 //this.listener.RunFinished( this.Results );
211 ThreadedTestRunner threadedRunner
= new ThreadedTestRunner( this );
212 threadedRunner
.BeginRun( listener
, filter
);
216 public virtual TestResult
EndRun()
218 TestSuiteResult suiteResult
= new TestSuiteResult( aggregateTest
, Test
.TestName
.FullName
);
219 foreach( TestRunner runner
in runners
)
220 suiteResult
.Results
.Add( runner
.EndRun() );
225 public virtual void CancelRun()
227 foreach( TestRunner runner
in runners
)
231 public virtual void Wait()
233 foreach( TestRunner runner
in runners
)
238 #region EventListener Members
239 public void TestStarted(TestName testName
)
241 this.listener
.TestStarted( testName
);
244 public void RunStarted(string name
, int testCount
)
246 // TODO: We may want to count how many runs are started
247 // Ignore - we provide our own
250 public void RunFinished(Exception exception
)
252 // Ignore - we provide our own
255 void NUnit
.Core
.EventListener
.RunFinished(TestResult result
)
257 // TODO: Issue combined RunFinished when all runs are done
260 public void SuiteFinished(TestSuiteResult result
)
262 this.listener
.SuiteFinished( result
);
265 public void TestFinished(TestCaseResult result
)
267 this.listener
.TestFinished( result
);
270 public void UnhandledException(Exception exception
)
272 this.listener
.UnhandledException( exception
);
275 public void TestOutput(TestOutput testOutput
)
277 this.listener
.TestOutput( testOutput
);
280 public void SuiteStarted(TestName suiteName
)
282 this.listener
.SuiteStarted( suiteName
);
286 #region InitializeLifetimeService Override
287 public override object InitializeLifetimeService()