22using Microsoft . Testing . Platform . TestHost ;
33using TUnit . Core ;
44using TUnit . Core . Data ;
5+ using TUnit . Core . Exceptions ;
56using TUnit . Core . Logging ;
67using TUnit . Core . ReferenceTracking ;
78using TUnit . Core . Tracking ;
@@ -84,12 +85,8 @@ await PropertyInjector.InjectPropertiesAsync(
8485 return await HandleSkippedTestAsync ( test , cancellationToken ) ;
8586 }
8687
87- // Check for failed dependencies and skip test if needed
88- await CheckDependenciesAndSetSkipReasonIfNeeded ( test ) ;
89- if ( ! string . IsNullOrEmpty ( test . Context . SkipReason ) )
90- {
91- return await HandleSkippedTestAsync ( test , cancellationToken ) ;
92- }
88+ // Check for failed dependencies and throw exception if test should be skipped
89+ CheckDependenciesAndThrowIfShouldSkip ( test ) ;
9390
9491 if ( test . Context is { RetryFunc : not null , TestDetails . RetryLimit : > 0 } )
9592 {
@@ -101,6 +98,11 @@ await PropertyInjector.InjectPropertiesAsync(
10198 await ExecuteTestWithHooksAsync ( test , instance , cancellationToken ) ;
10299 }
103100 }
101+ catch ( TestDependencyException e )
102+ {
103+ test . Context . SkipReason = e . Message ;
104+ return await HandleSkippedTestAsync ( test , cancellationToken ) ;
105+ }
104106 catch ( Exception ex )
105107 {
106108 HandleTestFailure ( test , ex ) ;
@@ -401,14 +403,14 @@ private static void RestoreHookContexts(TestContext context)
401403 }
402404 }
403405
404- private async Task CheckDependenciesAndSetSkipReasonIfNeeded ( AbstractExecutableTest test )
406+ private void CheckDependenciesAndThrowIfShouldSkip ( AbstractExecutableTest test )
405407 {
406408 if ( test . Dependencies . Length == 0 )
407409 {
408410 return ; // No dependencies to check
409411 }
410412
411- var failedDependencies = new List < string > ( ) ;
413+ var failedDependenciesNotAllowingProceed = new List < string > ( ) ;
412414
413415 foreach ( var dependency in test . Dependencies )
414416 {
@@ -419,21 +421,23 @@ private async Task CheckDependenciesAndSetSkipReasonIfNeeded(AbstractExecutableT
419421 var dependencyMetadata = test . Metadata . Dependencies . FirstOrDefault ( d =>
420422 DependencyMatches ( d , dependency ) ) ;
421423
422- // If no matching metadata found or ProceedOnFailure is false, skip the test
423- if ( dependencyMetadata == null || dependencyMetadata . ProceedOnFailure == false )
424+ // Get ProceedOnFailure setting (default to false if no metadata found)
425+ var proceedOnFailure = dependencyMetadata ? . ProceedOnFailure ?? false ;
426+
427+ // If this dependency doesn't allow proceeding on failure, add it to the list
428+ if ( ! proceedOnFailure )
424429 {
425- // Add to failed dependencies list for skip reason
426430 var dependencyName = GetDependencyDisplayName ( dependency ) ;
427- failedDependencies . Add ( dependencyName ) ;
431+ failedDependenciesNotAllowingProceed . Add ( dependencyName ) ;
428432 }
429433 }
430434 }
431435
432- if ( failedDependencies . Count > 0 )
436+ // Only throw if there are dependencies that don't allow proceeding
437+ if ( failedDependenciesNotAllowingProceed . Count > 0 )
433438 {
434- var dependencyNames = string . Join ( ", " , failedDependencies ) ;
435- test . Context . SkipReason = $ "Dependency failed: { dependencyNames } ";
436- await _logger . LogInformationAsync ( $ "Skipping test '{ test . Context . TestDetails . TestName } ' due to failed dependencies: { dependencyNames } ") ;
439+ var dependencyNames = string . Join ( ", " , failedDependenciesNotAllowingProceed ) ;
440+ throw new TestDependencyException ( dependencyNames , false ) ;
437441 }
438442 }
439443
0 commit comments