Skip to content

Commit

Permalink
Add support for TUnit Class Constructors (#1362)
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonCropp authored Nov 28, 2024
1 parent fd58c7b commit ad73307
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 29 deletions.
1 change: 1 addition & 0 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="NUnit" Version="4.2.2" />
<PackageVersion Include="MSTest" Version="3.6.3" />
Expand Down
21 changes: 21 additions & 0 deletions src/Verify.TUnit.Tests/ClassConstructor/ClassConstructor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Microsoft.Extensions.DependencyInjection;
using TUnit.Core.Interfaces;

public class ClassConstructor : IClassConstructor
{
static readonly IServiceProvider serviceProvider = CreateServiceProvider();

AsyncServiceScope scope;

public T Create<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(ClassConstructorMetadata classConstructorMetadata)
where T : class
{
scope = serviceProvider.CreateAsyncScope();
return ActivatorUtilities.GetServiceOrCreateInstance<T>(scope.ServiceProvider);
}

static IServiceProvider CreateServiceProvider() =>
new ServiceCollection()
.AddSingleton<string>("SingletonValue")
.BuildServiceProvider();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SingletonValue
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[ClassConstructor<ClassConstructor>]
[Arguments("2")]
public class ClassConstructorMixedWithArgumentTests(string service)
{
[Test]
public async Task Test()
{
await Assert.That(service).IsNotNull();
await Verify(service);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SingletonValue
10 changes: 10 additions & 0 deletions src/Verify.TUnit.Tests/ClassConstructor/ClassConstructorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[ClassConstructor<ClassConstructor>]
public class ClassConstructorTests(string service)
{
[Test]
public async Task Test()
{
await Assert.That(service).IsNotNull();
await Verify(service);
}
}
1 change: 1 addition & 0 deletions src/Verify.TUnit.Tests/Verify.TUnit.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="ProjectDefaults" PrivateAssets="all" />

<ProjectReference Include="..\TargetLibrary\TargetLibrary.csproj" />
Expand Down
41 changes: 12 additions & 29 deletions src/Verify.TUnit/TUnitExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,34 @@ static class TUnitExtensions
{
var methodParameterNames = details.MethodInfo.ParameterNames();

var names = GetConstructorParameterNames(details.ClassType, details.TestClassArguments.Length)
.ToList();
var constructorParameterNames = GetConstructorParameterNames(details);
if (methodParameterNames == null)
{
if (names.Count == 0)
if (constructorParameterNames.Count == 0)
{
return null;
}

return names;
return constructorParameterNames;
}

if (names.Count == 0 &&
methodParameterNames.Count == 0)
if (constructorParameterNames.Count == 0 &&
methodParameterNames.Count == 0)
{
return null;
}

return [.. names, .. methodParameterNames];
return [.. constructorParameterNames, .. methodParameterNames];
}

public static IEnumerable<string> GetConstructorParameterNames(this Type type, int argumentsLength)
static List<string> GetConstructorParameterNames(TestDetails details)
{
IEnumerable<string>? names = null;
foreach (var constructor in type.GetConstructors(BindingFlags.Instance | BindingFlags.Public))
var constructors = details.ClassType.GetConstructors(BindingFlags.Instance | BindingFlags.Public);
if (constructors.Length <= 1)
{
var parameters = constructor.GetParameters();
if (parameters.Length != argumentsLength)
{
continue;
}

if (names != null)
{
throw new($"Found multiple constructors with {argumentsLength} parameters. Unable to derive names of parameters. Instead use UseParameters to pass in explicit parameter.");
}

names = parameters.Select(_ => _.Name!);
}

if (names == null)
{
throw new($"Could not find constructor with {argumentsLength} parameters.");
return constructors[0].GetParameters().Select(_ => _.Name!).ToList();
}

return names;
throw new("Found multiple constructors. Unable to derive names of parameters. Instead use UseParameters to pass in explicit parameter.");
}
}
}

0 comments on commit ad73307

Please sign in to comment.