{"id":3164,"url":"https://github.com/plu/pxctest","last_synced_at":"2025-08-03T13:32:06.546Z","repository":{"id":56795838,"uuid":"74566572","full_name":"plu/pxctest","owner":"plu","description":"Execute tests in parallel on multiple iOS Simulators","archived":true,"fork":false,"pushed_at":"2018-07-05T09:18:54.000Z","size":1430,"stargazers_count":798,"open_issues_count":21,"forks_count":57,"subscribers_count":24,"default_branch":"master","last_synced_at":"2024-11-30T12:49:02.190Z","etag":null,"topics":["ios","parallel","simulator","xctest"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/plu.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-23T10:35:38.000Z","updated_at":"2024-11-19T08:22:56.000Z","dependencies_parsed_at":"2022-08-16T18:30:29.646Z","dependency_job_id":null,"html_url":"https://github.com/plu/pxctest","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plu%2Fpxctest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plu%2Fpxctest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plu%2Fpxctest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plu%2Fpxctest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/plu","download_url":"https://codeload.github.com/plu/pxctest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228548567,"owners_count":17935221,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","parallel","simulator","xctest"],"created_at":"2024-01-05T20:16:33.244Z","updated_at":"2024-12-07T01:30:39.454Z","avatar_url":"https://github.com/plu.png","language":"Swift","readme":"# Deprecation Warning\n\nXcode 9 perfectly supports executing tests in parallel without any 3rd party tool like pxctest. We suggest moving to `xcodebuild` for running tests in parallel on multiple Simulators.\n\n# pxctest\n\nExecute tests in parallel on multiple iOS Simulators.\n\n[![Build Status](https://travis-ci.org/plu/pxctest.svg?branch=master)](https://travis-ci.org/plu/pxctest)\n\n![screencast](static/screencast.gif?raw=true \"screencast\")\n\n## Installation\n\nTo install via Homebrew you can use the [plu/homebrew-pxctest](https://github.com/plu/homebrew-pxctest) tap:\n\n```shell\n$ brew tap plu/pxctest \u0026\u0026 brew install pxctest\n```\n\n## Usage\n\nCompile your tests with `build-for-testing`, example:\n\n```shell\n$ xcodebuild \\\n    -IDEBuildLocationStyle=Custom \\\n    -IDECustomBuildLocationType=Absolute \\\n    -IDECustomBuildProductsPath=\"$PWD/build/Products\" \\\n    -scheme 'MyApp' \\\n    -workspace 'MyApp.xcworkspace' \\\n    -destination 'platform=iOS Simulator,name=iPhone 5,OS=10.1' \\\n    build-for-testing\n```\n\nIn `build/Products` you should find a `.xctestrun` file. This can then be passed to `pxctest`:\n\n```shell\n$ pxctest \\\n    run-tests \\\n    --destination 'name=iPhone 5,os=iOS 9.3' \\\n    --destination 'name=iPhone 5,os=iOS 10.1' \\\n    --testrun build/Products/MyApp_iphonesimulator10.1-i386.xctestrun\n```\n\nThe `--destination` option can be passed in several times and will execute the tests in parallel on all Simulators.\n\n### run-tests options\n\nTo see a list of possible options, just run:\n\n```shell\n$ pxctest run-tests --help\n```\n\nMost of the options should be self-explanatory. If not, please open an issue or submit some pull request. However the `--defaults` option needs a special section here.\n\n#### run-tests --defaults\n\nThis option expects a path to a file, which contains some JSON. After loading this file, its content gets applied to the Simulator's defaults. On the top level the keys must be either a relative path or a domain where the defaults are located.\n\nExample: You can turn off all keyboard settings that you can find in the Simulator's Settings app by using following JSON content:\n\n```json\n{\n  \"com.apple.Preferences\": {\n    \"KeyboardAllowPaddle\": false,\n    \"KeyboardAssistant\": false,\n    \"KeyboardAutocapitalization\": false,\n    \"KeyboardAutocorrection\": false,\n    \"KeyboardCapsLock\": false,\n    \"KeyboardCheckSpelling\": false,\n    \"KeyboardPeriodShortcut\": false,\n    \"KeyboardPrediction\": false,\n    \"KeyboardShowPredictionBar\": false\n  }\n}\n```\n\n### Headless testing\n\nIt's possible to execute the tests without actually launching a `Simulator.app` window. This can be convenient because it will separate your test workflow from your development. If the tests run in the `Simulator.app` window and you launch your app during the test run from Xcode, it will stop the tests. There's not much we can do about that, it's just the way Xcode is handling `Simulator.app` - it takes control over all instances.\n\n![headless_screencast](static/headless_screencast.gif?raw=true \"headless screencast\")\n\nFirst you need to pre-boot some Simulators in the background, with a custom device set path:\n\n```shell\n$ mkdir /tmp/test-simulators\n$ pxctest boot-simulators \\\n    --deviceset /tmp/test-simulators \\\n    --destination 'name=iPhone 5,os=iOS 9.3' \\\n    --destination 'name=iPad Retina,os=iOS 9.3'\n```\n\nOnce the command has finished, the Simulators are in a usable state and we can begin running tests on them.\n\nTo launch your tests on these Simulators, you just need to pass the `--deviceset` option to the `run-tests` command:\n\n```shell\n$ pxctest run-tests \\\n    --testrun build/Products/KIF_iphonesimulator10.1-i386.xctestrun \\\n    --deviceset /tmp/test-simulators \\\n    --destination 'name=iPhone 5,os=iOS 9.3' \\\n    --destination 'name=iPad Retina,os=iOS 9.3' \\\n    --only 'KIF Tests:TappingTests'\n....................\nKIF Tests - iPhone 5 iOS 9.3 - Finished executing 10 tests after 25.252s. 0 Failures, 0 Unexpected\nKIF Tests - iPad Retina iOS 9.3 - Finished executing 10 tests after 25.119s. 0 Failures, 0 Unexpected\nTotal - Finished executing 20 tests. 0 Failures, 0 Unexpected\n```\n\nIf you still see some `Simulator.app` window showing up, it might have different reasons:\n\n* something went wrong pre-booting the devices earlier\n* you forgot the `--deviceset` option\n* you didn't pre-boot all devices that you're using as `--destination` options now\n\nYou can verify the state of your devices via:\n\n```shell\n$ xcrun simctl --set /tmp/test-simulators list\n== Devices ==\n-- iOS 9.3 --\n    iPhone 5 (716A9864-08BD-4200-96ED-20EA1E81BE65) (Booted)\n    iPad Retina (D2EB2BB9-8862-4F0D-A933-079C9BA0342A) (Booted)\n```\n\nThe `Booted` state here however does not mean \"is ready for launching apps or running tests\". After booting a device it enters the `Booted` state quickly, but still showing the loading bar above the Springboard (you can see that if you boot them via `Simulator.app` and keep watching the state that `xcrun simctl` reports).\n\nWhen you're finished running tests, you may wish to shut down running simulators to release their resources.\n\n```shell\n$ pxctest shutdown-simulators \\\n    --deviceset /tmp/test-simulators\n```\n\n## Development\n\n```shell\ngit clone --recursive https://github.com/plu/pxctest.git pxctest\ncd pxctest\nscripts/bootstrap.sh\nNSUnbufferedIO=YES xcodebuild -scheme pxctest test | xcpretty -c\n```\n\n## FBSimulatorControl\n\nThe functionality of `pxctest` would not be possible without the\ngreat [FBSimulatorControl Framework](https://github.com/facebook/FBSimulatorControl)\nprovided by [Lawrence Lomax](https://github.com/lawrencelomax) at\n[Facebook](https://github.com/facebook).\n\nThere are two command line tools that come with [FBSimulatorControl](https://github.com/facebook/FBSimulatorControl):\n\n* [fbsimctl](https://github.com/facebook/FBSimulatorControl/tree/master/fbsimctl) - command line interface to the FBSimulatorControl Framework\n* [fbxctest](https://github.com/facebook/FBSimulatorControl/tree/master/fbxctest) - test runner for running iOS testing bundles for the iOS Simulator Platform\n\nBoth of them are more flexible than `pxctest`, so it might be worth having a look at them.\n\n## Resource limits\n\nBy default the resource limitations (maximum processes per user, maximum open files) on Mac OS are quite small. There even seems to be a hard limit baked into the kernel of 2500 maximum processes per user. But there's some boot arguments that can be set to raise this limit to at least 5000.\n\nSo why is this important? A booted iPhone 7 Simulator is not just one process, it comes with a whole set of running processes. If you boot a couple Simulators at the same time, add your other running programs/processes on top of that, then you will hit these limits soon.\n\nFirst we [set the nvram boot argument](https://support.apple.com/en-ae/HT202528):\n\n```shell\n$ sudo nvram boot-args=\"serverperfmode=1 $(nvram boot-args 2\u003e/dev/null | cut -f 2-)\"\n```\n\nIf you're using Sierra, you will probably get an error message like\n```shell\nnvram: Error setting variable - 'boot-args': (iokit/common) general error\n```\nThis is because starting from Sierra the `nvram` command should be executed from the recovery partition. [more info here](https://support.apple.com/en-gb/HT206871)\nTo restart a mac from the recovery partition press \u003ckbd\u003eCMD\u003c/kbd\u003e+\u003ckbd\u003er\u003c/kbd\u003e during the boot procedure. From there open a terminal and insert the same command as before.\n\n\nNext step is to make `launchd` set the new limits:\n\n```shell\n$ sudo cp config/limit.maxfiles.plist /Library/LaunchDaemons/limit.maxfiles.plist\n$ sudo cp config/limit.maxproc.plist /Library/LaunchDaemons/limit.maxproc.plist\n```\n\nThe two files can be found in this repository:\n\n* [limit.maxfiles.plist](config/limit.maxfiles.plist)\n* [limit.maxproc.plist](config/limit.maxproc.plist)\n\nAnd we reboot! Afterwards you can check:\n\n```shell\n$ ulimit -a\ncore file size          (blocks, -c) 0\ndata seg size           (kbytes, -d) unlimited\nfile size               (blocks, -f) unlimited\nmax locked memory       (kbytes, -l) unlimited\nmax memory size         (kbytes, -m) unlimited\nopen files                      (-n) 524288\npipe size            (512 bytes, -p) 1\nstack size              (kbytes, -s) 8192\ncpu time               (seconds, -t) unlimited\nmax user processes              (-u) 5000\nvirtual memory          (kbytes, -v) unlimited\n```\n\nThe `open files` part should say `524288`, and `max user processes` should be `5000`.\n\nIf you are using Sierra, the output looks a bit different:\n\n```shell\n› ulimit -a\n-t: cpu time (seconds)              unlimited\n-f: file size (blocks)              unlimited\n-d: data seg size (kbytes)          unlimited\n-s: stack size (kbytes)             8192\n-c: core file size (blocks)         0\n-v: address space (kbytes)          unlimited\n-l: locked-in-memory size (kbytes)  unlimited\n-u: processes                       5000\n-n: file descriptors                524288\n```\nThe `open files` is now `file descriptors` and `max user processes` is renamed to `processes`.\n\n\n## Can't find the `.xctestrun`? \n\nWhen code coverage is enabled on the project specifying `IDECustomBuildProductsPath` to `xcodebuild` has no effect. Instead you can provide `derivedDataPath` and get the `.xctestrun` file from the directory.\n\nCompile your tests with `build-for-testing`, specifying `derivedDataPath`, for example:\n\n```shell\n$ xcodebuild \\\n    -derivedDataPath \"$PWD/derivedData\" \\\n    -scheme 'MyApp' \\\n    -workspace 'MyApp.xcworkspace' \\\n    -destination 'platform=iOS Simulator,name=iPhone 5,OS=10.1' \\\n    build-for-testing\n```\n\nIn `derivedData/Build/Intermediates/CodeCoverage/Products` you should find a `.xctestrun` file. This can then be passed to `pxctest`:\n\n```shell\n$ pxctest \\\n    run-tests \\\n    --destination 'name=iPhone 5,os=iOS 9.3' \\\n    --destination 'name=iPhone 5,os=iOS 10.1' \\\n    --testrun derivedData/Build/Intermediates/CodeCoverage/Products/MyApp_iphonesimulator10.1-i386.xctestrun\n```\n\n## Release version update\n\n1. Update `Info.plist` \u003e `CFBundleShortVersionString`\n2. Update `CHANGELOG.md`\n3. Ensure the latest stable Xcode version is installed and `xcode-select`ed.\n4. From project root directory run `./scripts/release.sh`\n5. Create a GitHub release: https://github.com/plu/pxctest/releases/new\n    * Specify the tag you just pushed in the dropdown.\n    * Set the release title to the new version number.\n    * Add the changelog section to the release description text box.\n    * Upload the portable zip you just built to the GitHub release binaries.\n    * Click \"Publish release\".\n6. Publish to Homebrew and CocoaPods: `./scripts/publish.sh`\n\n## License\n\n[MIT](LICENSE)\n","funding_links":[],"categories":["Tools","WebSocket","Swift"],"sub_categories":["Web View","Other free courses"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplu%2Fpxctest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplu%2Fpxctest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplu%2Fpxctest/lists"}