{"title":"Kiểm thử ứng dụng iOS tự động","slug":"automated-testing-ios","category":"guides","summary":"Sử dụng Synapse + Computer Control API để tự động hóa kiểm thử ứng dụng iOS qua Simulator.","audience":["human","llm"],"tags":["guide","ios","testing","automation"],"difficulty":"advanced","updated":"2026-06-27","word_count":407,"read_minutes":2,"lang":"vi","translated":true,"requested_lang":"vi","content_markdown":"\n# Kiểm thử ứng dụng iOS tự động\n\nKết hợp hệ thống bộ nhớ của Synapse với Computer Control API để xây dựng kiểm\nthử ứng dụng iOS điều khiển bởi LLM. LLM ghi nhớ kịch bản kiểm thử, học từ lỗi\nquá khứ và thích ứng với thay đổi UI.\n\n## Kiến trúc\n\n```\n┌──────────────┐    commands    ┌──────────────┐    screenshots    ┌──────────────┐\n│  LLM Agent   │ ─────────────▶│  Synapse     │ ────────────────▶ │  iOS Sim     │\n│  (Claude)    │               │  Computer    │ ◀──────────────── │  (via agent) │\n└──────────────┘               │  Control     │    results        └──────────────┘\n       │                       └──────────────┘\n       │ store/recall\n       ▼\n┌──────────────┐\n│  Memories    │ (test scenarios, past failures, UI patterns)\n└──────────────┘\n```\n\n## Điều kiện tiên quyết\n\n- Tài khoản Synapse + Mind Key\n- Synapse MCP server được cấu hình trong Claude Desktop\n- iOS Simulator với `screen-remote-agent` đã cài đặt\n- Máy tính đã đăng ký trong Synapse (xem [Computer Control API](/docs/api/computers))\n\n## Bước 1: Đăng ký máy tính Simulator\n\nTrên Mac chạy iOS Simulator:\n\n```bash\n# Get install code from Synapse\ncurl -X POST https://synapse.schaefer.zone/computers/install-code \\\n  -H \"Authorization: Bearer YOUR_MIND_KEY\" \\\n  -d '{\"computer_name\":\"ios-sim\"}'\n# → { \"install_code\": \"ic_...\" }\n\n# Run screen-remote-agent on the Mac\n# (uses the install code to register)\n```\n\n## Bước 2: Lưu kịch bản kiểm thử trong bộ nhớ\n\nLưu kịch bản kiểm thử tái sử dụng dưới dạng bộ nhớ:\n\n```python\nimport requests\n\ndef store_test_scenario(name, steps, app):\n    requests.post(f\"{URL}/memory\",\n        headers={\"Authorization\": f\"Bearer {MIND_KEY}\"},\n        json={\n            \"category\": \"skill\",\n            \"key\": f\"test_scenario_{name}\",\n            \"content\": f\"App: {app}\\nSteps:\\n\" + \"\\n\".join(steps),\n            \"tags\": [\"test\", \"ios\", app],\n            \"priority\": \"high\"\n        })\n\nstore_test_scenario(\"login_flow\", [\n    \"Launch app\",\n    \"Tap email field\",\n    \"Type test@example.com\",\n    \"Tap password field\",\n    \"Type password123\",\n    \"Tap Login button\",\n    \"Verify home screen appears\"\n], \"MyApp\")\n```\n\n## Bước 3: Thực thi kiểm thử điều khiển bởi LLM\n\nTrong Claude Desktop (với Synapse MCP đã cấu hình):\n\n```\nRun the login_flow test scenario on the iOS Simulator.\nTake a screenshot after each step and verify the expected UI.\nIf any step fails, store the failure as a memory so we can\navoid it next time.\n```\n\nClaude sẽ:\n\n1. Gọi `memory_search` để tìm bộ nhớ `test_scenario_login_flow`\n2. Gọi `computer_screenshot` để xem trạng thái hiện tại\n3. Thực thi mỗi bước qua `computer_command_queue` (click, type)\n4. Xác minh kết quả qua ảnh chụp màn hình\n5. Lưu bất kỳ lỗi nào dưới dạng bộ nhớ `mistake`\n\n## Bước 4: Kiểm thử tự sửa chữa\n\nKhi kiểm thử thất bại, lưu lỗi và cách khôi phục:\n\n```python\ndef store_test_failure(scenario, step, error, recovery):\n    requests.post(f\"{URL}/memory\",\n        headers={\"Authorization\": f\"Bearer {MIND_KEY}\"},\n        json={\n            \"category\": \"mistake\",\n            \"key\": f\"failure_{scenario}_{step}\",\n            \"content\": f\"Scenario: {scenario}\\nStep: {step}\\nError: {error}\\nRecovery: {recovery}\",\n            \"tags\": [\"test\", \"failure\", \"ios\", scenario],\n            \"priority\": \"high\"\n        })\n\n# Example\nstore_test_failure(\"login_flow\", \"tap_login\",\n    \"Login button not found at expected coordinates\",\n    \"Button moved due to new logo. Search by accessibility label instead.\")\n```\n\nLần tới LLM chạy kiểm thử, nó thu hồi lỗi và áp dụng khôi phục tự động.\n\n## Bước 5: Theo dõi kết quả kiểm thử\n\nTheo dõi lần chạy kiểm thử dưới dạng tác vụ:\n\n```python\ndef track_test_run(scenario, status, duration):\n    requests.post(f\"{URL}/mind/task\",\n        headers={\"Authorization\": f\"Bearer {MIND_KEY}\",\n                 \"Content-Type\": \"application/json\"},\n        json={\n            \"title\": f\"Test: {scenario}\",\n            \"description\": f\"Status: {status}, Duration: {duration}s\",\n            \"priority\": \"normal\"\n        })\n```\n\n## Lệnh phổ biến\n\n| Hành động | Lệnh |\n|--------|---------|\n| Khởi chạy Simulator | `xcrun simctl launch booted com.example.app` |\n| Ảnh chụp màn hình | `computer_screenshot` (qua Synapse MCP) |\n| Nhấp tại (x,y) | `computer_command_queue {type:\"click\", payload:{x,y}}` |\n| Nhập văn bản | `computer_command_queue {type:\"type\", payload:{text:\"...\"}}` |\n| Nhấn Home | `computer_command_queue {type:\"key\", payload:{keys:[\"Cmd\",\"Shift\",\"H\"]}}` |\n\n## Thực hành tốt nhất\n\n> [!TIP]\n> - **Lưu tọa độ UI dưới dạng bộ nhớ** — UI thay đổi, nhưng LLM có thể học lại\n> - **Sử dụng nhãn accessibility** — ổn định hơn tọa độ\n> - **Lưu dữ liệu kiểm thử riêng biệt** — sử dụng biến cho tên người dùng, mật khẩu\n> - **Chạy kiểm thử trong trạng thái sạch** — đặt lại Simulator giữa các lần chạy\n> - **Ghi ảnh chụp màn hình cho lỗi** — hữu ích cho gỡ lỗi\n\n## Bước tiếp theo\n\n- [Kiểm thử tự sửa chữa](/docs/guides/self-healing-tests)\n- [Computer Control API](/docs/api/computers)\n- [Thực hành tốt nhất về bộ nhớ](/docs/guides/memory-best-practices)\n","content_html":"<h1>Kiểm thử ứng dụng iOS tự động</h1>\n<p>Kết hợp hệ thống bộ nhớ của Synapse với Computer Control API để xây dựng kiểm\nthử ứng dụng iOS điều khiển bởi LLM. LLM ghi nhớ kịch bản kiểm thử, học từ lỗi\nquá khứ và thích ứng với thay đổi UI.</p>\n<h2>Kiến trúc</h2>\n<pre><code class=\"hljs language-plaintext\">┌──────────────┐    commands    ┌──────────────┐    screenshots    ┌──────────────┐\n│  LLM Agent   │ ─────────────▶│  Synapse     │ ────────────────▶ │  iOS Sim     │\n│  (Claude)    │               │  Computer    │ ◀──────────────── │  (via agent) │\n└──────────────┘               │  Control     │    results        └──────────────┘\n       │                       └──────────────┘\n       │ store/recall\n       ▼\n┌──────────────┐\n│  Memories    │ (test scenarios, past failures, UI patterns)\n└──────────────┘</code></pre><h2>Điều kiện tiên quyết</h2>\n<ul>\n<li>Tài khoản Synapse + Mind Key</li>\n<li>Synapse MCP server được cấu hình trong Claude Desktop</li>\n<li>iOS Simulator với <code>screen-remote-agent</code> đã cài đặt</li>\n<li>Máy tính đã đăng ký trong Synapse (xem <a href=\"/docs/api/computers\">Computer Control API</a>)</li>\n</ul>\n<h2>Bước 1: Đăng ký máy tính Simulator</h2>\n<p>Trên Mac chạy iOS Simulator:</p>\n<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># Get install code from Synapse</span>\ncurl -X POST https://synapse.schaefer.zone/computers/install-code \\\n  -H <span class=\"hljs-string\">&quot;Authorization: Bearer YOUR_MIND_KEY&quot;</span> \\\n  -d <span class=\"hljs-string\">&#x27;{&quot;computer_name&quot;:&quot;ios-sim&quot;}&#x27;</span>\n<span class=\"hljs-comment\"># → { &quot;install_code&quot;: &quot;ic_...&quot; }</span>\n\n<span class=\"hljs-comment\"># Run screen-remote-agent on the Mac</span>\n<span class=\"hljs-comment\"># (uses the install code to register)</span></code></pre><h2>Bước 2: Lưu kịch bản kiểm thử trong bộ nhớ</h2>\n<p>Lưu kịch bản kiểm thử tái sử dụng dưới dạng bộ nhớ:</p>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">import</span> requests\n\n<span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">store_test_scenario</span>(<span class=\"hljs-params\">name, steps, app</span>):\n    requests.post(<span class=\"hljs-string\">f&quot;<span class=\"hljs-subst\">{URL}</span>/memory&quot;</span>,\n        headers={<span class=\"hljs-string\">&quot;Authorization&quot;</span>: <span class=\"hljs-string\">f&quot;Bearer <span class=\"hljs-subst\">{MIND_KEY}</span>&quot;</span>},\n        json={\n            <span class=\"hljs-string\">&quot;category&quot;</span>: <span class=\"hljs-string\">&quot;skill&quot;</span>,\n            <span class=\"hljs-string\">&quot;key&quot;</span>: <span class=\"hljs-string\">f&quot;test_scenario_<span class=\"hljs-subst\">{name}</span>&quot;</span>,\n            <span class=\"hljs-string\">&quot;content&quot;</span>: <span class=\"hljs-string\">f&quot;App: <span class=\"hljs-subst\">{app}</span>\\nSteps:\\n&quot;</span> + <span class=\"hljs-string\">&quot;\\n&quot;</span>.join(steps),\n            <span class=\"hljs-string\">&quot;tags&quot;</span>: [<span class=\"hljs-string\">&quot;test&quot;</span>, <span class=\"hljs-string\">&quot;ios&quot;</span>, app],\n            <span class=\"hljs-string\">&quot;priority&quot;</span>: <span class=\"hljs-string\">&quot;high&quot;</span>\n        })\n\nstore_test_scenario(<span class=\"hljs-string\">&quot;login_flow&quot;</span>, [\n    <span class=\"hljs-string\">&quot;Launch app&quot;</span>,\n    <span class=\"hljs-string\">&quot;Tap email field&quot;</span>,\n    <span class=\"hljs-string\">&quot;Type test@example.com&quot;</span>,\n    <span class=\"hljs-string\">&quot;Tap password field&quot;</span>,\n    <span class=\"hljs-string\">&quot;Type password123&quot;</span>,\n    <span class=\"hljs-string\">&quot;Tap Login button&quot;</span>,\n    <span class=\"hljs-string\">&quot;Verify home screen appears&quot;</span>\n], <span class=\"hljs-string\">&quot;MyApp&quot;</span>)</code></pre><h2>Bước 3: Thực thi kiểm thử điều khiển bởi LLM</h2>\n<p>Trong Claude Desktop (với Synapse MCP đã cấu hình):</p>\n<pre><code class=\"hljs language-plaintext\">Run the login_flow test scenario on the iOS Simulator.\nTake a screenshot after each step and verify the expected UI.\nIf any step fails, store the failure as a memory so we can\navoid it next time.</code></pre><p>Claude sẽ:</p>\n<ol>\n<li>Gọi <code>memory_search</code> để tìm bộ nhớ <code>test_scenario_login_flow</code></li>\n<li>Gọi <code>computer_screenshot</code> để xem trạng thái hiện tại</li>\n<li>Thực thi mỗi bước qua <code>computer_command_queue</code> (click, type)</li>\n<li>Xác minh kết quả qua ảnh chụp màn hình</li>\n<li>Lưu bất kỳ lỗi nào dưới dạng bộ nhớ <code>mistake</code></li>\n</ol>\n<h2>Bước 4: Kiểm thử tự sửa chữa</h2>\n<p>Khi kiểm thử thất bại, lưu lỗi và cách khôi phục:</p>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">store_test_failure</span>(<span class=\"hljs-params\">scenario, step, error, recovery</span>):\n    requests.post(<span class=\"hljs-string\">f&quot;<span class=\"hljs-subst\">{URL}</span>/memory&quot;</span>,\n        headers={<span class=\"hljs-string\">&quot;Authorization&quot;</span>: <span class=\"hljs-string\">f&quot;Bearer <span class=\"hljs-subst\">{MIND_KEY}</span>&quot;</span>},\n        json={\n            <span class=\"hljs-string\">&quot;category&quot;</span>: <span class=\"hljs-string\">&quot;mistake&quot;</span>,\n            <span class=\"hljs-string\">&quot;key&quot;</span>: <span class=\"hljs-string\">f&quot;failure_<span class=\"hljs-subst\">{scenario}</span>_<span class=\"hljs-subst\">{step}</span>&quot;</span>,\n            <span class=\"hljs-string\">&quot;content&quot;</span>: <span class=\"hljs-string\">f&quot;Scenario: <span class=\"hljs-subst\">{scenario}</span>\\nStep: <span class=\"hljs-subst\">{step}</span>\\nError: <span class=\"hljs-subst\">{error}</span>\\nRecovery: <span class=\"hljs-subst\">{recovery}</span>&quot;</span>,\n            <span class=\"hljs-string\">&quot;tags&quot;</span>: [<span class=\"hljs-string\">&quot;test&quot;</span>, <span class=\"hljs-string\">&quot;failure&quot;</span>, <span class=\"hljs-string\">&quot;ios&quot;</span>, scenario],\n            <span class=\"hljs-string\">&quot;priority&quot;</span>: <span class=\"hljs-string\">&quot;high&quot;</span>\n        })\n\n<span class=\"hljs-comment\"># Example</span>\nstore_test_failure(<span class=\"hljs-string\">&quot;login_flow&quot;</span>, <span class=\"hljs-string\">&quot;tap_login&quot;</span>,\n    <span class=\"hljs-string\">&quot;Login button not found at expected coordinates&quot;</span>,\n    <span class=\"hljs-string\">&quot;Button moved due to new logo. Search by accessibility label instead.&quot;</span>)</code></pre><p>Lần tới LLM chạy kiểm thử, nó thu hồi lỗi và áp dụng khôi phục tự động.</p>\n<h2>Bước 5: Theo dõi kết quả kiểm thử</h2>\n<p>Theo dõi lần chạy kiểm thử dưới dạng tác vụ:</p>\n<pre><code class=\"hljs language-python\"><span class=\"hljs-keyword\">def</span> <span class=\"hljs-title function_\">track_test_run</span>(<span class=\"hljs-params\">scenario, status, duration</span>):\n    requests.post(<span class=\"hljs-string\">f&quot;<span class=\"hljs-subst\">{URL}</span>/mind/task&quot;</span>,\n        headers={<span class=\"hljs-string\">&quot;Authorization&quot;</span>: <span class=\"hljs-string\">f&quot;Bearer <span class=\"hljs-subst\">{MIND_KEY}</span>&quot;</span>,\n                 <span class=\"hljs-string\">&quot;Content-Type&quot;</span>: <span class=\"hljs-string\">&quot;application/json&quot;</span>},\n        json={\n            <span class=\"hljs-string\">&quot;title&quot;</span>: <span class=\"hljs-string\">f&quot;Test: <span class=\"hljs-subst\">{scenario}</span>&quot;</span>,\n            <span class=\"hljs-string\">&quot;description&quot;</span>: <span class=\"hljs-string\">f&quot;Status: <span class=\"hljs-subst\">{status}</span>, Duration: <span class=\"hljs-subst\">{duration}</span>s&quot;</span>,\n            <span class=\"hljs-string\">&quot;priority&quot;</span>: <span class=\"hljs-string\">&quot;normal&quot;</span>\n        })</code></pre><h2>Lệnh phổ biến</h2>\n<table>\n<thead>\n<tr>\n<th>Hành động</th>\n<th>Lệnh</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>Khởi chạy Simulator</td>\n<td><code>xcrun simctl launch booted com.example.app</code></td>\n</tr>\n<tr>\n<td>Ảnh chụp màn hình</td>\n<td><code>computer_screenshot</code> (qua Synapse MCP)</td>\n</tr>\n<tr>\n<td>Nhấp tại (x,y)</td>\n<td><code>computer_command_queue {type:&quot;click&quot;, payload:{x,y}}</code></td>\n</tr>\n<tr>\n<td>Nhập văn bản</td>\n<td><code>computer_command_queue {type:&quot;type&quot;, payload:{text:&quot;...&quot;}}</code></td>\n</tr>\n<tr>\n<td>Nhấn Home</td>\n<td><code>computer_command_queue {type:&quot;key&quot;, payload:{keys:[&quot;Cmd&quot;,&quot;Shift&quot;,&quot;H&quot;]}}</code></td>\n</tr>\n</tbody></table>\n<h2>Thực hành tốt nhất</h2>\n<div class=\"callout callout-ok\"></div><h2>Bước tiếp theo</h2>\n<ul>\n<li><a href=\"/docs/guides/self-healing-tests\">Kiểm thử tự sửa chữa</a></li>\n<li><a href=\"/docs/api/computers\">Computer Control API</a></li>\n<li><a href=\"/docs/guides/memory-best-practices\">Thực hành tốt nhất về bộ nhớ</a></li>\n</ul>\n","urls":{"html":"/docs/guides/automated-testing-ios","text":"/docs/guides/automated-testing-ios?format=text","json":"/docs/guides/automated-testing-ios?format=json","llm":"/docs/guides/automated-testing-ios?format=llm"},"translations_available":["en","zh","hi","es","fr","ar","pt","ru","ja","de","it","ko","nl","pl","tr","sv","vi","th","id","uk"]}