Xcode Source Editor Extensionを使って、実装ファイルとテストファイルをトグルジャンプする

# まえがき

以前、[iOS Test Night #4](https://testnight.connpass.com/event/54316/)という勉強会にて、[テストを書かない言い訳をした結果ｗｗｗｗｗｗｗ // Speaker Deck](https://speakerdeck.com/takasek/tesutowoshu-kanaiyan-iyi-wositajie-guo-wwwwwww)という発表①をしました。
この発表①は[もっと過去のiOS Test Nightで行った発表](https://speakerdeck.com/takasek/tesutowoshu-kanaiyan-iyi-wosasetekure)⓪を枕にした発表です。ややこしいな。
発表⓪にて、テストファイルと実装ファイルって
<img width="165" alt="distance.png" src="https://qiita-image-store.s3.amazonaws.com/0/34405/689d11e1-2a9c-54f9-441a-6c089c51aa67.png">
みたいに距離があると気軽に行き来するには辛すぎるよねと話したんですが、そしたら
<blockquote class="hatena-bookmark-comment"><a class="comment-info" href="http://b.hatena.ne.jp/entry/326981554/comment/vvakame" data-user-id="vvakame" data-entry-url="http://b.hatena.ne.jp/entry/s/speakerdeck.com/takasek/tesutowoshu-kanaiyan-iyi-wosasetekure" data-original-href="https://speakerdeck.com/takasek/tesutowoshu-kanaiyan-iyi-wosasetekure" data-entry-favicon="https://cdn-ak.favicon.st-hatena.com/?url=https%3A%2F%2Fspeakerdeck.com%2F" data-user-icon="/users/vv/vvakame/profile.gif">テストを書かない言い訳をさせてくれ // Speaker Deck</a><br><p style="clear: left">Java+Eclipse時代はプロダクトコードとテストコードをトグル的に行き来できるプラグイン入れてたけどXcode+Swiftはそういうのないの？？？</p><a class="datetime" href="/vvakame/20170317#bookmark-326981554"><span class="datetime-body">2017/03/17 10:15</span></a></blockquote><script src="https://b.st-hatena.com/js/comment-widget.js" charset="utf-8" async></script>
と言われたので、それができるように
https://github.com/takasek/XCJumpToTests/blob/master/xcode_toggleImplAndTests.scpt
というAppleScriptスクリプトを作りました、というのが発表①の内容でした。

![o.gif](https://qiita-image-store.s3.amazonaws.com/0/34405/98a9d3cc-63a2-3168-7d9d-d146fa07aad6.gif)


# xcode_toggleImplAndTests.scpt の使い方

Xcodeには `Custom Behavior` という機能があり、任意のスクリプトをワンタップで実行できます。
適当な場所にスクリプトを置いて、設定からTrigger Hot Keyを設定します。
<img width="800" alt="behavior.png" src="https://qiita-image-store.s3.amazonaws.com/0/34405/1eb29529-c4f6-e95a-2bd6-a8e94055a73e.png">

`Hoge.swift` で実行したら `HogeTests.swift あるいは HogeSpec.swift` に、
`HogeTests.swift あるいは HogeSpec.swift` で実行したら `Hoge.swift` にジャンプします。

ありがたいことに、今も活用していただけてると報告を受けることがあります。
けど問題もありまして、

# xcode_toggleImplAndTests.scpt の問題点

AppleScript読みづらいし書きづらい。
本当ならメンテしやすいように、SwiftかObj-Cで書きたいものです。
というかXcode Source Editor Extensionで実現できれば最高なんだけどなー…
と思ってたところで、それを可能にするワークアラウンドを思いつきました。
その詳細については数日前の別記事 [続・Xcode Source Editor Extensionの世界 〜XPCとScripting Bridge〜 - Qiita](https://qiita.com/takasek/items/8b782848adc9ddff125e) で解説しました。

# xcode_toggleImplAndTests.scpt をXcode Source Editor Extension化してみた

これが成果物です。
https://github.com/takasek/XCJumpToTests

## 使い方

1. プロジェクトをcloneして、Xcodeで開きます
2. プロビジョニングプロファイルを書き替えてArchiveします
3. 出来上がった `.app` を実行すると、コンピュータにXcode Source Editor Extensionがインストールされます
4. 設定画面からホットキーを設定します

![image.png](https://qiita-image-store.s3.amazonaws.com/0/34405/b9a21de5-a97b-c2d6-4529-fb00982aeef4.png)

スクリプトバージョンに比べて、ビルドする手間が増えましたが、スクリプトの置き場所に悩む必要はなくなり、Xcodeと統合された安心感と格段のメンテナンス性が手に入りました。

## 制限

プロジェクトをArchiveする必要があるということは、有料のApple Developer Program登録をしている必要があるということです。
有料登録していない開発者であれば、AppleScript版が役に立つことでしょう。

# XcodeとのScripting Bridge によるテストの可能性

「テスト自動化」の話かって言われると少し苦しい記事内容になってしまった気がするので、ついでに、最後にそれっぽい話でお茶を濁しましょう。

Xcode Scripting Bridgeには次のようなインタフェースがあります。

```objc
- (XcodeSchemeActionResult *) testWithCommandLineArguments:(id)withCommandLineArguments withEnvironmentVariables:(id)withEnvironmentVariables;
```

ちなみに `XcodeSchemeActionResult` ってのはこんな奴。

```objc
// An object describing the result of performing a scheme action command.
@interface XcodeSchemeActionResult : SBObject <XcodeGenericMethods>

- (SBElementArray<XcodeBuildError *> *) buildErrors;
- (SBElementArray<XcodeBuildWarning *> *) buildWarnings;
- (SBElementArray<XcodeAnalyzerIssue *> *) analyzerIssues;
- (SBElementArray<XcodeTestFailure *> *) testFailures;

- (NSString *) id;  // The unique identifier for the scheme.
@property (readonly) BOOL completed;  // Whether this scheme action has completed (sucessfully or otherwise) or not.
@property XcodeSchemeActionResultStatus status;  // Indicates the status of the scheme action.
@property (copy) NSString *errorMessage;  // If the result's status is "error occurred", this will be the error message; otherwise, this will be "missing value".
@property (copy) NSString *buildLog;  // If this scheme action performed a build, this will be the text of the build log.


@end
```

これを使えば、Apple ScriptやXcode Source Editor Extensionからテストを実行し、終了を監視することも可能かもしれません。
……そこ、誰得とか言わない。

# 完全に余談ですが

今回のプロジェクトを準備していたところ、Twitterにてこんな反応をいただきました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/takasek?ref_src=twsrc%5Etfw">@takasek</a> さんの.swiftとtest.swiftを行き来できるスクリプトを使ってViewControllerとViewModelを行き来できるようしたい気持ちがすごい <a href="https://t.co/Uoh7WBVqpP">https://t.co/Uoh7WBVqpP</a></p>&mdash; mego (@mego_) <a href="https://twitter.com/mego_/status/937914321866129408?ref_src=twsrc%5Etfw">2017年12月5日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">私もFlux版を作って使ってます👍<br>アシスタントエディタ側でも効かせたいですよねー。</p>&mdash; ネバダ最速の鈴木 (@toshi0383) <a href="https://twitter.com/toshi0383/status/937921838415454208?ref_src=twsrc%5Etfw">2017年12月5日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

確かに、ジャンプ元・ジャンプ先を求めるロジックだけ切り出してエディットできるようにすれば、もっと柔軟で使い道が広がるなーと思いつつ、今回そこまでやると完全にアドベントカレンダーの趣旨から抜けてしまうのでやりませんでした。
近いうちに、そこまで実現したXcode Source Editor Extensionをリリースしたいなと思いました。