Skip to content

Conversation

@voonfoo
Copy link

@voonfoo voonfoo commented Dec 15, 2025

Adds optional filter parameters to the run_tests MCP tool.

Summary by CodeRabbit

  • New Features
    • Added test filtering capabilities to run specific tests by name, group, category, or assembly. Multiple filter criteria can be applied simultaneously for more efficient and targeted test execution.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 15, 2025

Walkthrough

Test filtering support is added across the test runner infrastructure by introducing a new TestFilterOptions class and updating test execution method signatures to accept optional filter parameters for test names, group names, category names, and assembly names in both C# and Python implementations.

Changes

Cohort / File(s) Summary
Test filtering infrastructure
MCPForUnity/Editor/Services/ITestRunnerService.cs
Added new public class TestFilterOptions with string array properties for TestNames, GroupNames, CategoryNames, and AssemblyNames. Updated ITestRunnerService.RunTestsAsync() method signature to accept optional TestFilterOptions filterOptions parameter (defaulting to null). Updated XML documentation.
Test runner implementation
MCPForUnity/Editor/Services/TestRunnerService.cs
Updated RunTestsAsync() method signature to accept optional TestFilterOptions filterOptions parameter. Modified filter construction to populate testNames, groupNames, categoryNames, and assemblyNames properties from the filterOptions object when provided.
C# test execution
MCPForUnity/Editor/Tools/RunTests.cs
Added using System.Linq directive. Implemented ParseFilterOptions() helper method to construct TestFilterOptions from input parameters (returns null if no filters). Implemented ParseStringArray() helper to normalize single strings or arrays into string arrays. Updated test execution call to pass parsed filter options to RunTestsAsync().
Python test execution
Server/src/services/tools/run_tests.py
Expanded run_tests() function signature with optional parameters: test_names, group_names, category_names, and assembly_names. Replaced Field() decorator usage with Annotated metadata strings for mode and timeout_seconds. Implemented _coerce_string_list() helper to normalize string or list inputs. Integrated filters into request payload dictionary as testNames, groupNames, categoryNames, and assemblyNames.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Verify TestFilterOptions property names align between C# and Python parameter naming conventions
  • Confirm null-handling consistency across both implementations (filterOptions defaults, conditional null-coalescing operators)
  • Check that filter parameter field names in the request payload match the expected API contract on the server side

Poem

🐰 Hop, hop! The tests can now be sorted,
By name and group and category be courted,
With filters fine, we choose which ones to run,
No more all-or-nothing—selective testing's fun!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Feat: Add test filtering options to run_tests tool' accurately describes the main change—adding test filtering capabilities to the run_tests tool across multiple components.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
Server/src/services/tools/run_tests.py (1)

73-82: String/list coercion helper is robust; consider centralizing if reused

_coerce_string_list defensively normalizes None, a single string, or a list into list[str] | None, trimming and dropping empty values. This matches how the C# side treats filters. If you end up adding more tools with similar semantics, it could be worth extracting this into a shared utility to avoid subtle divergence over time.

MCPForUnity/Editor/Tools/RunTests.cs (1)

76-135: Filter parsing from JObject is defensive and matches the transport contract

ParseFilterOptions and ParseStringArray together:

  • Accept both single string and array forms for each filter.
  • Ignore missing, null, empty, or whitespace-only values.
  • Return null for each filter when there’s nothing meaningful, and null for the whole TestFilterOptions when all filters are absent.

This lines up with the Python side sending only non-empty arrays for testNames, groupNames, categoryNames, and assemblyNames, and cleanly distinguishes “no filtering” from “filtered run”.

You could optionally widen ParseStringArray to also accept non-string JValues by calling ToString() on non-null scalars, mirroring the Python helper’s behavior, but it’s not strictly necessary given the current contract.

MCPForUnity/Editor/Services/ITestRunnerService.cs (1)

7-32: TestFilterOptions shape aligns with Unity filter fields and caller docs

The new POCO cleanly captures the four optional filter dimensions (tests, groups, categories, assemblies) and matches the JSON contract used in RunTests.cs and run_tests.py. The XML comments are precise and mirror the tool-side descriptions, which will help keep the transport and service layers in sync.

If you later construct TestFilterOptions from other call sites, consider normalizing empty arrays to null at the edges so the “null or empty arrays are ignored” guarantee is enforced in one place rather than relying on callers to avoid empty arrays.

MCPForUnity/Editor/Services/TestRunnerService.cs (1)

97-104: Filter wiring cleanly maps TestFilterOptions into Unity’s Filter

Constructing new Filter { testMode = mode, testNames = filterOptions?.TestNames, groupNames = filterOptions?.GroupNames, categoryNames = filterOptions?.CategoryNames, assemblyNames = filterOptions?.AssemblyNames } is exactly what the Unity Test Runner expects and keeps the “unfiltered” case simple when filterOptions is null.

If you ever want to strictly enforce the “empty arrays are ignored” contract at this layer, you could normalize any zero-length arrays on filterOptions to null before creating the Filter, but with current callers this isn’t required.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8fe73be and b69bf44.

📒 Files selected for processing (4)
  • MCPForUnity/Editor/Services/ITestRunnerService.cs (2 hunks)
  • MCPForUnity/Editor/Services/TestRunnerService.cs (2 hunks)
  • MCPForUnity/Editor/Tools/RunTests.cs (3 hunks)
  • Server/src/services/tools/run_tests.py (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-03T16:00:55.839Z
Learnt from: dsarno
Repo: CoplayDev/unity-mcp PR: 0
File: :0-0
Timestamp: 2025-09-03T16:00:55.839Z
Learning: ComponentResolver in UnityMcpBridge/Editor/Tools/ManageGameObject.cs is a nested static class within ManageGameObject, not a sibling type. The `using static MCPForUnity.Editor.Tools.ManageGameObject;` import is required to access ComponentResolver methods directly without the outer class qualifier.

Applied to files:

  • MCPForUnity/Editor/Tools/RunTests.cs
🧬 Code graph analysis (3)
MCPForUnity/Editor/Tools/RunTests.cs (2)
MCPForUnity/Editor/Services/ITestRunnerService.cs (3)
  • Task (43-43)
  • Task (50-50)
  • TestFilterOptions (11-32)
MCPForUnity/Editor/Services/TestRunnerService.cs (6)
  • Task (34-59)
  • Task (61-140)
  • Task (256-284)
  • TestRunResult (343-395)
  • TestRunResult (345-349)
  • TestRunResult (369-394)
MCPForUnity/Editor/Services/TestRunnerService.cs (2)
MCPForUnity/Editor/Services/ITestRunnerService.cs (3)
  • Task (43-43)
  • Task (50-50)
  • TestFilterOptions (11-32)
MCPForUnity/Editor/Tools/RunTests.cs (2)
  • Task (19-74)
  • TestFilterOptions (76-101)
MCPForUnity/Editor/Services/ITestRunnerService.cs (2)
MCPForUnity/Editor/Tools/RunTests.cs (1)
  • TestFilterOptions (76-101)
MCPForUnity/Editor/Services/TestRunnerService.cs (3)
  • TestRunResult (343-395)
  • TestRunResult (345-349)
  • TestRunResult (369-394)
🔇 Additional comments (6)
Server/src/services/tools/run_tests.py (2)

48-53: Filterable run_tests signature looks consistent with editor-side API

The additional optional parameters for test, group, category, and assembly names read cleanly and match the C# TestFilterOptions shape. Keeping them as str | list[str] | None preserves backward compatibility while giving the MCP layer flexibility.


89-105: Filter parameters are only sent when non-empty and use the expected keys

The mapping of normalized lists to params["testNames"/"groupNames"/"categoryNames"/"assemblyNames"] is correct and matches what MCPForUnity.Editor.Tools.RunTests expects. Guarding on truthiness ensures you don’t send empty arrays, which keeps the payload minimal and leaves “no filter” as the default behavior on the Unity side.

MCPForUnity/Editor/Tools/RunTests.cs (2)

2-2: System.Linq import is warranted

using System.Linq; is required for the LINQ calls in ParseStringArray (Where, Select, ToArray), so this addition is appropriate and not redundant.


46-53: Plumbing of filterOptions into RunTestsAsync preserves existing behavior

Computing filterOptions once and passing it into RunTestsAsync(parsedMode.Value, filterOptions) is clean. When no filters are provided, ParseFilterOptions returns null, so the service call remains effectively identical to the previous unfiltered behavior while enabling filtered runs when any filter is set.

MCPForUnity/Editor/Services/ITestRunnerService.cs (1)

46-50: Extended RunTestsAsync signature is backward-compatible for in-repo callers

Adding TestFilterOptions filterOptions = null to RunTestsAsync keeps the default path (run all tests) intact while exposing filtering in a single, typed parameter. With the default value, in-repo call sites that are recompiled don’t need changes unless they want to pass filters explicitly.

MCPForUnity/Editor/Services/TestRunnerService.cs (1)

61-61: RunTestsAsync overload aligns with interface and preserves locking semantics

Updating the implementation signature to RunTestsAsync(TestMode mode, TestFilterOptions filterOptions = null) keeps it consistent with ITestRunnerService while reusing the existing _operationLock/PlayMode-guarding logic unchanged. The added parameter is plumbed through without altering concurrency behavior.

@voonfoo voonfoo changed the title Add test filtering options to run_tests tool Feat: Add test filtering options to run_tests tool Dec 15, 2025
Copy link
Contributor

@msanatan msanatan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't tested it but code looks solid

@msanatan
Copy link
Contributor

If no other maintainer gets to it, I'll block out some testing time tomorrow and merge it in

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants