Skip to content

Commit 7472a1f

Browse files
committed
fix: update invocation logic for dynamic test expressions
1 parent 6c9dfec commit 7472a1f

File tree

3 files changed

+92
-13
lines changed

3 files changed

+92
-13
lines changed

TUnit.Engine/Building/Collectors/AotTestDataCollector.cs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -205,21 +205,32 @@ private Task<TestMetadata> CreateMetadataFromDynamicDiscoveryResult(DynamicDisco
205205
throw new InvalidOperationException("Dynamic test method expression is null");
206206
}
207207

208-
// Since we're in AOT mode, we need to handle this differently
209-
// The expression should already be compiled in source generation
208+
// Extract method info from the expression
210209
var lambdaExpression = result.TestMethod as LambdaExpression;
211210
if (lambdaExpression == null)
212211
{
213212
throw new InvalidOperationException("Dynamic test method must be a lambda expression");
214213
}
215214

216-
var compiledExpression = lambdaExpression.Compile();
215+
MethodInfo? methodInfo = null;
216+
if (lambdaExpression.Body is MethodCallExpression methodCall)
217+
{
218+
methodInfo = methodCall.Method;
219+
}
220+
else if (lambdaExpression.Body is UnaryExpression { Operand: MethodCallExpression unaryMethodCall })
221+
{
222+
methodInfo = unaryMethodCall.Method;
223+
}
224+
225+
if (methodInfo == null)
226+
{
227+
throw new InvalidOperationException("Could not extract method info from dynamic test expression");
228+
}
229+
217230
var testInstance = instance ?? throw new InvalidOperationException("Test instance is null");
218231

219-
// The expression is already bound to the correct method with arguments
220-
// so we just need to invoke it with the instance
221-
var invokeMethod = compiledExpression.GetType().GetMethod("Invoke")!;
222-
var invokeResult = invokeMethod.Invoke(compiledExpression, [testInstance]);
232+
// Use the provided args from TestMethodArguments instead of the expression's placeholder values
233+
var invokeResult = methodInfo.Invoke(testInstance, args);
223234

224235
if (invokeResult is Task task)
225236
{

TUnit.Engine/Discovery/ReflectionTestDataCollector.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2049,20 +2049,32 @@ private Task<TestMetadata> CreateMetadataFromDynamicDiscoveryResult(DynamicDisco
20492049
throw new InvalidOperationException("Dynamic test method expression is null");
20502050
}
20512051

2052-
// Since we're in reflection mode, we can compile and invoke the expression
2052+
// Extract method info from the expression
20532053
var lambdaExpression = result.TestMethod as System.Linq.Expressions.LambdaExpression;
20542054
if (lambdaExpression == null)
20552055
{
20562056
throw new InvalidOperationException("Dynamic test method must be a lambda expression");
20572057
}
20582058

2059-
var compiledExpression = lambdaExpression.Compile();
2059+
MethodInfo? methodInfo = null;
2060+
if (lambdaExpression.Body is System.Linq.Expressions.MethodCallExpression methodCall)
2061+
{
2062+
methodInfo = methodCall.Method;
2063+
}
2064+
else if (lambdaExpression.Body is System.Linq.Expressions.UnaryExpression { Operand: System.Linq.Expressions.MethodCallExpression unaryMethodCall })
2065+
{
2066+
methodInfo = unaryMethodCall.Method;
2067+
}
2068+
2069+
if (methodInfo == null)
2070+
{
2071+
throw new InvalidOperationException("Could not extract method info from dynamic test expression");
2072+
}
2073+
20602074
var testInstance = instance ?? throw new InvalidOperationException("Test instance is null");
20612075

2062-
// The expression is already bound to the correct method with arguments
2063-
// so we just need to invoke it with the instance
2064-
var invokeMethod = compiledExpression.GetType().GetMethod("Invoke")!;
2065-
var invokeResult = invokeMethod.Invoke(compiledExpression, [testInstance]);
2076+
// Use the provided args from TestMethodArguments instead of the expression's placeholder values
2077+
var invokeResult = methodInfo.Invoke(testInstance, args);
20662078

20672079
if (invokeResult is Task task)
20682080
{
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using TUnit.TestProject.Attributes;
2+
3+
#pragma warning disable TUnitWIP0001
4+
5+
namespace TUnit.TestProject.Bugs._3173;
6+
7+
[EngineTest(ExpectedResult.Pass)]
8+
public class DynamicTestArgumentsTests
9+
{
10+
[DynamicTestBuilder]
11+
public void BuildDynamicTests(DynamicTestBuilderContext context)
12+
{
13+
string testValue = "abc";
14+
15+
context.AddTest(new DynamicTest<DynamicTestArgumentsTests>
16+
{
17+
TestMethod = (@class) => @class.TestStringArgument(DynamicTestHelper.Argument<string>()),
18+
TestMethodArguments = [testValue],
19+
});
20+
21+
int testInt = 42;
22+
context.AddTest(new DynamicTest<DynamicTestArgumentsTests>
23+
{
24+
TestMethod = (@class) => @class.TestIntArgument(DynamicTestHelper.Argument<int>()),
25+
TestMethodArguments = [testInt],
26+
});
27+
28+
context.AddTest(new DynamicTest<DynamicTestArgumentsTests>
29+
{
30+
TestMethod = (@class) => @class.TestMultipleArguments(
31+
DynamicTestHelper.Argument<string>(),
32+
DynamicTestHelper.Argument<int>(),
33+
DynamicTestHelper.Argument<bool>()),
34+
TestMethodArguments = ["test", 123, true],
35+
});
36+
}
37+
38+
public async Task TestStringArgument(string value)
39+
{
40+
await Assert.That(value).IsNotNull();
41+
await Assert.That(value).IsEqualTo("abc");
42+
}
43+
44+
public async Task TestIntArgument(int value)
45+
{
46+
await Assert.That(value).IsNotEqualTo(0);
47+
await Assert.That(value).IsEqualTo(42);
48+
}
49+
50+
public async Task TestMultipleArguments(string str, int num, bool flag)
51+
{
52+
await Assert.That(str).IsEqualTo("test");
53+
await Assert.That(num).IsEqualTo(123);
54+
await Assert.That(flag).IsTrue();
55+
}
56+
}

0 commit comments

Comments
 (0)