xcode-test
Run Xcode project tests on simulators or devices by specifying project path, scheme, and destination, with options for test plans, specific tests, and result bundles.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| projectPath | Yes | Xcode 프로젝트 또는 워크스페이스 경로 | |
| scheme | Yes | 테스트할 스킴 | |
| destination | Yes | 테스트 대상 (예: 'platform=iOS Simulator,name=iPhone 14') | |
| testPlan | No | 사용할 테스트 플랜 이름 | |
| onlyTesting | No | 실행할 특정 테스트 식별자들 (예: ['ModuleTests/ClassTests/testMethod']) | |
| skipTesting | No | 건너뛸 테스트 식별자들 | |
| resultBundlePath | No | 테스트 결과 번들 저장 경로 | |
| buildForTesting | No | 테스트용 빌드만 수행할지 여부 | |
| testWithoutBuilding | No | 빌드 없이 테스트만 수행할지 여부 |
Implementation Reference
- src/index.ts:219-294 (handler)The async handler function that implements the core logic of the 'xcode-test' tool. It builds an xcodebuild test command using the provided parameters (project path, scheme, destination, etc.) and executes it via the executeCommand helper.async ({ projectPath, scheme, destination, testPlan, onlyTesting = [], skipTesting = [], resultBundlePath, buildForTesting = false, testWithoutBuilding = false }) => { try { console.error(`Xcode 테스트 실행: ${projectPath}, Scheme: ${scheme}`); let command = `xcodebuild`; // 워크스페이스인지 프로젝트인지 확인 if (projectPath.endsWith(".xcworkspace")) { command += ` -workspace "${projectPath}"`; } else { command += ` -project "${projectPath}"`; } command += ` -scheme "${scheme}"`; command += ` -destination "${destination}"`; // 테스트 모드 설정 if (buildForTesting) { command += ` build-for-testing`; } else if (testWithoutBuilding) { command += ` test-without-building`; } else { command += ` test`; // 기본 모드: 빌드 후 테스트 } // 테스트 플랜 설정 if (testPlan) { command += ` -testPlan "${testPlan}"`; } // 특정 테스트만 실행 if (onlyTesting.length > 0) { for (const test of onlyTesting) { command += ` -only-testing:"${test}"`; } } // 특정 테스트 건너뛰기 if (skipTesting.length > 0) { for (const test of skipTesting) { command += ` -skip-testing:"${test}"`; } } // 결과 번들 경로 설정 if (resultBundlePath) { command += ` -resultBundlePath "${resultBundlePath}"`; } console.error(`실행할 테스트 명령어: ${command}`); // 테스트 명령어 실행 try { const { stdout, stderr } = await executeCommand(command); let resultText = "테스트 결과:\n"; if (stdout) resultText += `${stdout}\n`; if (stderr) resultText += `STDERR:\n${stderr}\n`; return { content: [{ type: "text", text: resultText }] }; } catch (error: any) { throw error; } } catch (error: any) { console.error(`Xcode 테스트 오류: ${error.message}`); return { content: [{ type: "text", text: `Xcode 테스트 중 오류가 발생했습니다:\n${error.message}\n${error.stderr || ''}` }], isError: true }; }
- src/index.ts:208-218 (schema)The Zod schema defining the input parameters for the 'xcode-test' tool, including projectPath, scheme, destination, and optional test filtering and configuration options.{ projectPath: z.string().describe("Xcode 프로젝트 또는 워크스페이스 경로"), scheme: z.string().describe("테스트할 스킴"), destination: z.string().describe("테스트 대상 (예: 'platform=iOS Simulator,name=iPhone 14')"), testPlan: z.string().optional().describe("사용할 테스트 플랜 이름"), onlyTesting: z.array(z.string()).optional().describe("실행할 특정 테스트 식별자들 (예: ['ModuleTests/ClassTests/testMethod'])"), skipTesting: z.array(z.string()).optional().describe("건너뛸 테스트 식별자들"), resultBundlePath: z.string().optional().describe("테스트 결과 번들 저장 경로"), buildForTesting: z.boolean().optional().describe("테스트용 빌드만 수행할지 여부"), testWithoutBuilding: z.boolean().optional().describe("빌드 없이 테스트만 수행할지 여부") },
- src/index.ts:206-296 (registration)The server.tool registration call that defines and registers the 'xcode-test' tool with its schema and handler function.server.tool( "xcode-test", { projectPath: z.string().describe("Xcode 프로젝트 또는 워크스페이스 경로"), scheme: z.string().describe("테스트할 스킴"), destination: z.string().describe("테스트 대상 (예: 'platform=iOS Simulator,name=iPhone 14')"), testPlan: z.string().optional().describe("사용할 테스트 플랜 이름"), onlyTesting: z.array(z.string()).optional().describe("실행할 특정 테스트 식별자들 (예: ['ModuleTests/ClassTests/testMethod'])"), skipTesting: z.array(z.string()).optional().describe("건너뛸 테스트 식별자들"), resultBundlePath: z.string().optional().describe("테스트 결과 번들 저장 경로"), buildForTesting: z.boolean().optional().describe("테스트용 빌드만 수행할지 여부"), testWithoutBuilding: z.boolean().optional().describe("빌드 없이 테스트만 수행할지 여부") }, async ({ projectPath, scheme, destination, testPlan, onlyTesting = [], skipTesting = [], resultBundlePath, buildForTesting = false, testWithoutBuilding = false }) => { try { console.error(`Xcode 테스트 실행: ${projectPath}, Scheme: ${scheme}`); let command = `xcodebuild`; // 워크스페이스인지 프로젝트인지 확인 if (projectPath.endsWith(".xcworkspace")) { command += ` -workspace "${projectPath}"`; } else { command += ` -project "${projectPath}"`; } command += ` -scheme "${scheme}"`; command += ` -destination "${destination}"`; // 테스트 모드 설정 if (buildForTesting) { command += ` build-for-testing`; } else if (testWithoutBuilding) { command += ` test-without-building`; } else { command += ` test`; // 기본 모드: 빌드 후 테스트 } // 테스트 플랜 설정 if (testPlan) { command += ` -testPlan "${testPlan}"`; } // 특정 테스트만 실행 if (onlyTesting.length > 0) { for (const test of onlyTesting) { command += ` -only-testing:"${test}"`; } } // 특정 테스트 건너뛰기 if (skipTesting.length > 0) { for (const test of skipTesting) { command += ` -skip-testing:"${test}"`; } } // 결과 번들 경로 설정 if (resultBundlePath) { command += ` -resultBundlePath "${resultBundlePath}"`; } console.error(`실행할 테스트 명령어: ${command}`); // 테스트 명령어 실행 try { const { stdout, stderr } = await executeCommand(command); let resultText = "테스트 결과:\n"; if (stdout) resultText += `${stdout}\n`; if (stderr) resultText += `STDERR:\n${stderr}\n`; return { content: [{ type: "text", text: resultText }] }; } catch (error: any) { throw error; } } catch (error: any) { console.error(`Xcode 테스트 오류: ${error.message}`); return { content: [{ type: "text", text: `Xcode 테스트 중 오류가 발생했습니다:\n${error.message}\n${error.stderr || ''}` }], isError: true }; } } );