Description
When running the TUnit NUnit migration code fixer, methods that implement interface members with void return types are incorrectly converted to async Task methods. This breaks the interface implementation because the interface still expects void.
Steps to Reproduce
- Create a project with classes that implement interfaces (like
IInterceptor, IProxyGenerationHook) and use NUnit assertions
- Add TUnit packages
- Run
dotnet format analyzers --severity info --diagnostics TUNU0001
- Build the project
Expected Behavior
Methods that implement interface members should NOT have their return type changed. The assertions should either:
- Use synchronous assertion patterns
- Be left unchanged for manual migration
Actual Behavior
Interface implementation methods are converted to async, causing build errors:
error CS0738: 'ChangeProxyTargetInterceptor' does not implement interface member
'IInterceptor.Intercept(IInvocation)'. 'ChangeProxyTargetInterceptor.Intercept(IInvocation)'
cannot implement 'IInterceptor.Intercept(IInvocation)' because it does not have the
matching return type of 'void'.
Example
Interface definition (not modified by migration):
public interface IInterceptor
{
void Intercept(IInvocation invocation);
}
Before migration:
public class ChangeProxyTargetInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var targetAccessor = invocation.Proxy as IProxyTargetAccessor;
Assert.IsNotNull(targetAccessor);
targetAccessor.DynProxySetTarget(target);
invocation.Proceed();
}
}
After migration (current - broken):
public class ChangeProxyTargetInterceptor : IInterceptor
{
public async Task Intercept(IInvocation invocation) // <-- Breaks interface implementation
{
var targetAccessor = invocation.Proxy as IProxyTargetAccessor;
await Assert.That(targetAccessor).IsNotNull();
targetAccessor.DynProxySetTarget(target);
invocation.Proceed();
}
}
Expected after migration:
Option 1 - Use synchronous pattern:
public class ChangeProxyTargetInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var targetAccessor = invocation.Proxy as IProxyTargetAccessor;
Assert.That(targetAccessor).IsNotNull().Wait(); // or synchronous alternative
targetAccessor.DynProxySetTarget(target);
invocation.Proceed();
}
}
Option 2 - Leave unchanged for manual migration:
public class ChangeProxyTargetInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
var targetAccessor = invocation.Proxy as IProxyTargetAccessor;
Assert.IsNotNull(targetAccessor); // Left for manual migration
targetAccessor.DynProxySetTarget(target);
invocation.Proceed();
}
}
Detection Suggestion
The code fixer could detect interface implementations by checking:
- If the containing class implements any interfaces
- If the method signature matches an interface member
- If so, don't convert to async
Impact
This is a critical issue because it generates code that cannot compile.
Environment
- TUnit version: 1.9.91
- .NET version: .NET 8.0
- OS: Windows
Description
When running the TUnit NUnit migration code fixer, methods that implement interface members with
voidreturn types are incorrectly converted toasync Taskmethods. This breaks the interface implementation because the interface still expectsvoid.Steps to Reproduce
IInterceptor,IProxyGenerationHook) and use NUnit assertionsdotnet format analyzers --severity info --diagnostics TUNU0001Expected Behavior
Methods that implement interface members should NOT have their return type changed. The assertions should either:
Actual Behavior
Interface implementation methods are converted to async, causing build errors:
Example
Interface definition (not modified by migration):
Before migration:
After migration (current - broken):
Expected after migration:
Option 1 - Use synchronous pattern:
Option 2 - Leave unchanged for manual migration:
Detection Suggestion
The code fixer could detect interface implementations by checking:
Impact
This is a critical issue because it generates code that cannot compile.
Environment