@@ -87,8 +87,8 @@ void defineReflectiveTests(Type type) {
8787 {
8888 var isSolo = _hasAnnotationInstance (classMirror, soloTest);
8989 var className = MirrorSystem .getName (classMirror.simpleName);
90- group = _Group (isSolo, _combineNames (_currentSuiteName, className),
91- classMirror.testLocation );
90+ group = _Group (
91+ isSolo, _combineNames (_currentSuiteName, className), classMirror);
9292 _currentGroups.add (group);
9393 }
9494
@@ -151,10 +151,24 @@ void _addTestsIfTopLevelSuite() {
151151 if (_currentSuiteLevel == 0 ) {
152152 void runTests ({required bool allGroups, required bool allTests}) {
153153 for (var group in _currentGroups) {
154+ var runTestCount = 0 ;
154155 if (allGroups || group.isSolo) {
155156 for (var test in group.tests) {
156157 if (allTests || test.isSolo) {
157- test_package.test (test.name, test.function,
158+ if (! test.isSkipped) {
159+ runTestCount += 1 ;
160+ }
161+ test_package.test (test.name, () async {
162+ await group.ensureSetUpClass ();
163+ try {
164+ await test.function ();
165+ } finally {
166+ runTestCount -= 1 ;
167+ if (runTestCount == 0 ) {
168+ group.tearDownClass ();
169+ }
170+ }
171+ },
158172 timeout: test.timeout,
159173 skip: test.isSkipped,
160174 location: test.location);
@@ -210,14 +224,14 @@ bool _hasSkippedTestAnnotation(MethodMirror method) =>
210224 _hasAnnotationInstance (method, skippedTest);
211225
212226Future <Object ?> _invokeSymbolIfExists (
213- InstanceMirror instanceMirror , Symbol symbol) {
227+ ObjectMirror objectMirror , Symbol symbol) {
214228 Object ? invocationResult;
215229 InstanceMirror ? closure;
216230 try {
217- closure = instanceMirror .getField (symbol);
231+ closure = objectMirror .getField (symbol);
218232 // ignore: avoid_catching_errors
219233 } on NoSuchMethodError {
220- // ignore
234+ // ignore: empty_catches
221235 }
222236
223237 if (closure is ClosureMirror ) {
@@ -307,10 +321,13 @@ class _AssertFailingTest {
307321class _Group {
308322 final bool isSolo;
309323 final String name;
310- final test_package.TestLocation ? location;
311324 final List <_Test > tests = < _Test > [];
312325
313- _Group (this .isSolo, this .name, this .location);
326+ /// For static group-wide operations eg `setUpClass` and `tearDownClass` .
327+ final ClassMirror _classMirror;
328+ Future <Object ?>? _setUpCompletion;
329+
330+ _Group (this .isSolo, this .name, this ._classMirror);
314331
315332 bool get hasSoloTest => tests.any ((test) => test.isSolo);
316333
@@ -327,6 +344,19 @@ class _Group {
327344 tests.add (_Test (isSolo, fullName, function, timeout? ._timeout,
328345 memberMirror.testLocation));
329346 }
347+
348+ /// Runs group-wide setup if it has not been started yet,
349+ /// ensuring it only runs once for a group. Set up runs and
350+ /// completes before any test of the group runs
351+ Future <Object ?> ensureSetUpClass () =>
352+ _setUpCompletion ?? = _invokeSymbolIfExists (_classMirror, #setUpClass);
353+
354+ /// Runs group-wide tear down iff [ensureSetUpClass] was called at least once.
355+ /// Must be called once and only called after all tests of the group have
356+ /// completed
357+ void tearDownClass () => _setUpCompletion != null
358+ ? _invokeSymbolIfExists (_classMirror, #tearDownClass)
359+ : null ;
330360}
331361
332362/// A marker annotation used to instruct dart2js to keep reflection information
0 commit comments