Skip to content

Commit bf76cee

Browse files
committed
feat: added param:returnWithLogs for run_tests tool, count pass/fail without groups
1 parent c709528 commit bf76cee

File tree

5 files changed

+32
-22
lines changed

5 files changed

+32
-22
lines changed

Editor/Services/ITestRunnerService.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ public interface ITestRunnerService
2222
/// </summary>
2323
/// <param name="testMode">The test mode to run (EditMode or PlayMode).</param>
2424
/// <param name="returnOnlyFailures">If true, only failed test results are included in the output.</param>
25+
/// <param name="returnWithLogs">If true, all logs are included in the output.</param>
2526
/// <param name="testFilter">A filter string to select specific tests to run.</param>
2627
/// <returns>Task that resolves with test results when tests are complete</returns>
27-
Task<JObject> ExecuteTestsAsync(TestMode testMode, bool returnOnlyFailures, string testFilter);
28+
Task<JObject> ExecuteTestsAsync(TestMode testMode, bool returnOnlyFailures, bool returnWithLogs, string testFilter);
2829
}
29-
}
30+
}

Editor/Services/TestRunnerService.cs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public class TestRunnerService : ITestRunnerService, ICallbacks
2121
private readonly TestRunnerApi _testRunnerApi;
2222
private TaskCompletionSource<JObject> _tcs;
2323
private bool _returnOnlyFailures;
24+
private bool _returnWithLogs;
2425
private List<ITestResultAdaptor> _results;
2526

2627
/// <summary>
@@ -77,13 +78,15 @@ public async Task<List<ITestAdaptor>> GetAllTestsAsync(string testModeFilter = "
7778
/// </summary>
7879
/// <param name="testMode">The test mode to run (EditMode or PlayMode).</param>
7980
/// <param name="returnOnlyFailures">If true, only failed test results are included in the output.</param>
81+
/// <param name="returnWithLogs">If true, all logs are included in the output.</param>
8082
/// <param name="testFilter">A filter string to select specific tests to run.</param>
8183
/// <returns>Task that resolves with test results when tests are complete</returns>
82-
public async Task<JObject> ExecuteTestsAsync(TestMode testMode, bool returnOnlyFailures, string testFilter = "")
84+
public async Task<JObject> ExecuteTestsAsync(TestMode testMode, bool returnOnlyFailures, bool returnWithLogs, string testFilter = "")
8385
{
8486
_tcs = new TaskCompletionSource<JObject>();
8587
_results = new List<ITestResultAdaptor>();
8688
_returnOnlyFailures = returnOnlyFailures;
89+
_returnWithLogs = returnWithLogs;
8790
var filter = new Filter { testMode = testMode };
8891

8992
if (!string.IsNullOrEmpty(testFilter))
@@ -191,30 +194,30 @@ private async Task<JObject> WaitForCompletionAsync(int timeoutSeconds)
191194

192195
private JObject BuildResultJson(List<ITestResultAdaptor> results, ITestResultAdaptor result)
193196
{
194-
int pass = results.Count(r => r.ResultState == "Passed");
195-
int fail = results.Count(r => r.ResultState == "Failed");
196-
int skip = results.Count(r => r.ResultState == "Skipped");
197-
198197
var arr = new JArray(results
198+
.Where(r => !r.HasChildren)
199199
.Where(r => !_returnOnlyFailures || r.ResultState == "Failed")
200200
.Select(r => new JObject {
201201
["name"] = r.Name,
202202
["fullName"] = r.FullName,
203203
["state"] = r.ResultState,
204204
["message"] = r.Message,
205-
["duration"] = r.Duration
205+
["duration"] = r.Duration,
206+
["logs"] = _returnWithLogs ? r.Output : null,
207+
["stackTrace"] = r.StackTrace
206208
}));
207209

210+
int testCount = result.PassCount + result.SkipCount + result.FailCount;
208211
return new JObject {
209212
["success"] = true,
210213
["type"] = "text",
211-
["message"] = $"{result.Test.Name} test run completed: {pass}/{results.Count} passed - {fail}/{results.Count} failed - {skip}/{results.Count} skipped",
214+
["message"] = $"{result.Test.Name} test run completed: {result.PassCount}/{testCount} passed - {result.FailCount}/{testCount} failed - {result.SkipCount}/{testCount} skipped",
212215
["resultState"] = result.ResultState,
213216
["durationSeconds"] = result.Duration,
214-
["testCount"] = results.Count,
215-
["passCount"] = pass,
216-
["failCount"] = fail,
217-
["skipCount"] = skip,
217+
["testCount"] = testCount,
218+
["passCount"] = result.PassCount,
219+
["failCount"] = result.FailCount,
220+
["skipCount"] = result.SkipCount,
218221
["results"] = arr
219222
};
220223
}

Editor/Tools/RunTestsTool.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public override async void ExecuteAsync(JObject parameters, TaskCompletionSource
3737
string testModeStr = parameters?["testMode"]?.ToObject<string>() ?? "EditMode";
3838
string testFilter = parameters?["testFilter"]?.ToObject<string>(); // Optional
3939
bool returnOnlyFailures = parameters?["returnOnlyFailures"]?.ToObject<bool>() ?? false; // Optional
40+
bool returnWithLogs = parameters?["returnWithLogs"]?.ToObject<bool>() ?? false; // Optional
4041

4142
TestMode testMode = TestMode.EditMode;
4243

@@ -48,7 +49,7 @@ public override async void ExecuteAsync(JObject parameters, TaskCompletionSource
4849
McpLogger.LogInfo($"Executing RunTestsTool: Mode={testMode}, Filter={testFilter ?? "(none)"}");
4950

5051
// Call the service to run tests
51-
JObject result = await _testRunnerService.ExecuteTestsAsync(testMode, returnOnlyFailures, testFilter);
52+
JObject result = await _testRunnerService.ExecuteTestsAsync(testMode, returnOnlyFailures, returnWithLogs, testFilter);
5253
tcs.SetResult(result);
5354
}
5455
}

Server~/build/tools/runTestsTool.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ const toolName = 'run_tests';
55
const toolDescription = 'Runs Unity\'s Test Runner tests';
66
const paramsSchema = z.object({
77
testMode: z.string().optional().default('EditMode').describe('The test mode to run (EditMode or PlayMode) - defaults to EditMode (optional)'),
8-
testFilter: z.string().optional().default('').describe('The specific test filter to run (e.g. specific test name or namespace) (optional)'),
9-
returnOnlyFailures: z.boolean().optional().default(true).describe('Whether to show only failed tests in the results (optional)')
8+
testFilter: z.string().optional().default('').describe('The specific test filter to run (e.g. specific test name or class name, must include namespace) (optional)'),
9+
returnOnlyFailures: z.boolean().optional().default(true).describe('Whether to show only failed tests in the results (optional)'),
10+
returnWithLogs: z.boolean().optional().default(false).describe('Whether to return the test logs in the results (optional)')
1011
});
1112
/**
1213
* Creates and registers the Run Tests tool with the MCP server
@@ -41,14 +42,15 @@ export function registerRunTestsTool(server, mcpUnity, logger) {
4142
* @throws McpUnityError if the request to Unity fails
4243
*/
4344
async function toolHandler(mcpUnity, params = {}) {
44-
const { testMode = 'EditMode', testFilter = '', returnOnlyFailures = true } = params;
45+
const { testMode = 'EditMode', testFilter = '', returnOnlyFailures = true, returnWithLogs = false } = params;
4546
// Create and wait for the test run
4647
const response = await mcpUnity.sendRequest({
4748
method: toolName,
4849
params: {
4950
testMode,
5051
testFilter,
51-
returnOnlyFailures
52+
returnOnlyFailures,
53+
returnWithLogs
5254
}
5355
});
5456
// Process the test results

Server~/src/tools/runTestsTool.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ const toolName = 'run_tests';
1010
const toolDescription = 'Runs Unity\'s Test Runner tests';
1111
const paramsSchema = z.object({
1212
testMode: z.string().optional().default('EditMode').describe('The test mode to run (EditMode or PlayMode) - defaults to EditMode (optional)'),
13-
testFilter: z.string().optional().default('').describe('The specific test filter to run (e.g. specific test name or namespace) (optional)'),
14-
returnOnlyFailures: z.boolean().optional().default(true).describe('Whether to show only failed tests in the results (optional)')
13+
testFilter: z.string().optional().default('').describe('The specific test filter to run (e.g. specific test name or class name, must include namespace) (optional)'),
14+
returnOnlyFailures: z.boolean().optional().default(true).describe('Whether to show only failed tests in the results (optional)'),
15+
returnWithLogs: z.boolean().optional().default(false).describe('Whether to return the test logs in the results (optional)')
1516
});
1617

1718
/**
@@ -56,7 +57,8 @@ async function toolHandler(mcpUnity: McpUnity, params: any = {}): Promise<CallTo
5657
const {
5758
testMode = 'EditMode',
5859
testFilter = '',
59-
returnOnlyFailures = true
60+
returnOnlyFailures = true,
61+
returnWithLogs = false
6062
} = params;
6163

6264
// Create and wait for the test run
@@ -65,7 +67,8 @@ async function toolHandler(mcpUnity: McpUnity, params: any = {}): Promise<CallTo
6567
params: {
6668
testMode,
6769
testFilter,
68-
returnOnlyFailures
70+
returnOnlyFailures,
71+
returnWithLogs
6972
}
7073
});
7174

0 commit comments

Comments
 (0)