画面サイズ変わるとぶっ壊れるAuto LayoutをUnit Testで把握する

  • 47
    Like
  • 2
    Comment
More than 1 year has passed since last update.

TL;DR

ライブラリ書きました。
https://github.com/ypresto/AutoLayoutLint

これを入れておけば↓みたいな感じでViewControllerごとにぶっ壊れているかどうかチェックしてくれます。

screenshot.png

セットアップ

iOS 8.0+のプロジェクトで使えます。

CarthageかCocoaPodsでAutoLayoutLintをインストールしたらこんな感じのテストを書けば追加done!
(画面サイズはサポートしているものだけ残して削ったり、iPadの解像度を足したりしてください。)

@import AutoLayoutLint;

@interface YourAutoLayoutLintTests : PSTAutoLayoutLintTestCase

@end

@implementation YourAutoLayoutLintTests

+ (NSArray<NSValue *> *)screenSizes
{
    return @[
        [self valueWithWidth:320 height:480], // iPhone 4S
        [self valueWithWidth:480 height:320],
        [self valueWithWidth:320 height:568], // iPhone 5, 5S
        [self valueWithWidth:568 height:320],
        [self valueWithWidth:375 height:667], // iPhone 6, 6S
        [self valueWithWidth:667 height:375],
        [self valueWithWidth:414 height:736], // iPhone 6 Plus, 6S Plus
        [self valueWithWidth:736 height:414],
    ];
}

- (void)testDummy
{
    // NOTE: Workaround for Xcode bug.
    // Refer: https://github.com/ypresto/AutoLayoutLint/issues/1
}

@end

Auto Layoutの課題点

Auto Layoutは簡単に様々な画面サイズへの対応が可能で便利な反面、Constraintsを上手に設計しないと、画面サイズが変わった時に "Unable to simultaneously satisfy constraints" と言われて壊れたりします。

(設計についてはこちらもどうぞ→) http://qiita.com/yuya_presto/items/08b0656f67a59c8c2d03

チーム内でも実際にサイズが変わることによってConstraintsが壊れたりしたのですが、これをレビューなどで発見・修正するためにはConstraintsの設計について習熟していないと難しいという点が課題に上がりました。特に今回はiPhone 6(S) / 6(S) Plus解像度への対応を行うために大変多くのViewControllerについてAuto Layoutの新規投入や修正を行うこととなり、壊れている箇所がないか不安が残りました。

それprivate APIででき(ry

そこで最低限のチェックを自動化できないかというアイデアを持ち出しました。

チームメンバーがmisplaced="YES"になっている(Interface Builder上で黄色い三角出てる状態)xmlをgrepで見つけるチェックを作ってくれたのですが、かつてあった(はずの)ambiguous="YES"(赤丸出ていて壊れている状態)がxml上に現れなくなっていました。

一方Auto Layoutが壊れるのは大抵Interface Builder上の表示と異なる画面サイズになった場合なので、それを何とかして見つけるには実際にLayout Engineをぶん回す他なさそうだなぁという考えに至りました。

そこで、画面サイズをいろいろ変えてレイアウト処理を実際に実行してみて、Auto Layoutが警告を出す際の(private APIな)メソッド呼び出しをぶんどってTest FailureにするUnit Testをライブラリ化してみました。

※実際のViewControllerのviewDidLoadが叩かれると通信とかしちゃう場合がありそうなのでviewDidLoadもぶんどってstubにしちゃいます。

既知の制限

UITableViewとかUICollectionViewとか動的要素が強いのでまだチェックできないのですが適当にdataSource埋めたらどうにかなりそうなので、なんとかしようと思っています・・。
UINavigationControllerにpushしているわけじゃなく、nav/tab barの高さをエミュレートしているわけではないので、縦方向のチェックは若干不完全かもしれません。これは対策を考えます。
あと、compression resistance priorityとかcontent hugging priorityとかで起きるambiguous状態も発見したいのですがまだ未サポートです。priorityの件に関しては後で記事書こうと思います。