Skip to content

Abstract Class [Before(Test)] breakage #2887

@viceroypenguin

Description

@viceroypenguin

The following code builds and displays ActualTestClas.Test1 as a test with TUnit 0.25.21:

using System.Diagnostics.CodeAnalysis;
using TUnit.Core.Interfaces;

public interface IServiceProvider;

public sealed class DependencyInjectionClassConstructor : IClassConstructor
{
    public object Create([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type, ClassConstructorMetadata classConstructorMetadata)
    {
        throw new NotImplementedException();
    }
}

public abstract class BaseTestClass(IServiceProvider serviceProvider)
{
    [Before(Test)]
    public Task Hook() => Task.CompletedTask;

}

[ClassConstructor<DependencyInjectionClassConstructor>]
public sealed class ActualTestClass(IServiceProvider serviceProvider)
    : BaseTestClass(serviceProvider)
{
    [Test]
    public void Test1() { }
}

However, updating to 0.55.6 (and modifying Create() to fit the updated interface), I get the following error during test discovery:

[ConsoleApp1.dll] Unhandled exception. System.TypeInitializationException: The type initializer for 'TUnit.Generated.Hooks.GeneratedHookRegistry' threw an exception.
 ---> System.InvalidOperationException: Failed to initialize hook registry: Object reference not set to an instance of an object.
 ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at TUnit.Generated.Hooks.GeneratedHookRegistry.<>c.<PopulateSourcesDictionaries>b__1_1() in D:\viceroypenguin\ConsoleApp1\obj\Debug\net9.0\TUnit.Core.SourceGenerator\TUnit.Core.SourceGenerator.Generators.HookMetadataGenerator\GeneratedHookSource.g.cs:line 50
   at TUnit.Core.ClassMetadata.<>c__DisplayClass3_0.<GetOrAdd>b__0(String _)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
...

I think the issue is that the hook generator is looking for the constructor to BaseTestClass, however that constructor is (correctly) protected since it can only be constructed as an instance of a subclass. This works in earlier versions of TUnit.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions