Swift で MessagePack-RPC
ねこじゃらしの y-okubo と申します。
今回は、Swift で MessagePack-RPC を実現するライブラリの使い方を紹介します。
MessagePack-RPC については、こちらをご覧ください。
www.slideshare.net
ひとことで言えば、MessagePack (JSON) を使った RPC です。
各言語にライブラリが用意されており、異なる言語で作ったアプリ間でプロセス間通信をするのに便利です。
なぜか公式にはリストアップされていないのですが、Objective-C 版もあります(CocoaPods 対応がありがたい)。
今回は、コレを Swift から使ってみることにしました。
プロジェクトの作成
まず、Xcode で適当なプロジェクトを作成します。 今回は OS X - Application - Command Line Tool のプロジェクトを作成します。
ターミナルでそのディレクトリまで移動して、以下のコマンドで CocoaPods をインストールします。
pod init
この後は、作成された Podfile に使用するライブラリを追加していきます。 Podfile を編集して、以下の内容を追加します。
pod 'MPMessagePack'
以下のコマンドを実行してライブラリをインストールします。
pod install
CocoaPods のライブラリを Xcode で使うには、先のコマンドで生成された .xcworkspace ファイルを開きます。
サンプルコード
簡単なコードを書いて動作確認をしてみます。
まずはサーバのリクエストハンドラを追加します。
RPC が呼び出されると必ずこのコードが実行されます。
メソッド名で分岐することで RPC 呼出しに対応したコードを記述できます。
今回は実験的なコードなので、そのような分岐はせず同じような戻り値を返しています。
func serverRequestHandler(messageId: NSNumber?, method: String?, params: [AnyObject]?, completion: (MPRequestCompletion)?) { if let method = method, let params = params { print("(Server) method:", method) print("(Server) params:", params) } completion!(nil, "Return from server(\(method))") }
サーバを起動するコードを追加します。
リクエストハンドラを設定して、ポート 5001 番でサーバを起動してみます。
// Server var server: MPMessagePackServer = MPMessagePackServer() server.requestHandler = serverRequestHandler do { try server.openWithPort(5001) } catch let error as NSError { print(error) }
クライアントのコードを追加します。
こちらは非同期実行のコードになります。
var client: MPMessagePackClient = MPMessagePackClient() client.openWithHost("127.0.0.1", port: 5001, completion: {error in client.sendRequestWithMethod("method_hoge", params: ["hoge", "42"], messageId: 1, completion: {error, result in if let error = error { print("Error:", error) } }) })
同期実行のコードは以下になります。 こちらは Exception を throw するので do ~ try ~ catch で例外ハンドリングをする必要があります。
client.openWithHost("127.0.0.1", port: 5001, completion: {error in do { try print(client.sendRequestWithMethod("method_fuga", params: [], messageId: 1, timeout: 2.0)) } catch let error as NSError { print("Error:", error) } })
注意点として、Command Line Tool でプロジェクトを作成している場合は、以下のコードも追加してください(このコードを追加しないと動きません)。
このコードで無限ループを回してクライアントからのリクエストを待ちます。
NSRunLoop.currentRunLoop().run()
では、コードを実行してみます。
2016-08-12 15:35:40.222 MsgpackRpcSwiftExample[11273:1429215] -[MPMessagePackServer connectionWithInputStream:outputStream:]:38: [Server] Client connected (Server) method: method_fuga (Server) params: [] (Server) method: method_hoge (Server) params: [hoge, 42]
クライアントからの RPC 呼出しに対してサーバが値を受け取っているのがおわかりいただけるかと思います。
まとめ
MessagePack-RPC を Swift から使う方法について簡単に紹介いたしました。
他の言語についてもライブラリが存在するので、異なる言語間でプロセス間通信を行うような処理が必要になったとき、気軽に使えて便利です。
最近はマイクロサービス化によりコンポーネントの疎結合化が加速しており、設計の都合やチームのスキルセットによって言語を使い分けるシーンも増えているのではないでしょうか。
そのようなときに、それらコンポーネントを繋ぐ方法として MessagePack-RPC は有力な選択肢になり得ると思います。
MessagePack-RPC を使う上でこの記事がお役に立てば幸いです。
お知らせ
ねこじゃらしでは Swift に限らず Ruby や JavaScript のプログラマ、UI/UX デザイナを募集しております。
ご興味をお持ちいただけましたら、以下のリンクからお問い合わせください。
Go の パッケージ管理ツールは glide がイイ感じ
ねこじゃらしの y-okubo と申します。
今回は、仕事で Go を書いたときに使ったパッケージ管理ツール glide について簡単にですが、紹介させていただきます。
そもそも Go にはパッケージ管理を行うための仕組みがありません。
パッケージ管理をし易くするための仕組みが、現行の 1.6 で導入された Vendoring です。
Vendoring の詳しい説明はググっていただくとして、実際にはパッケージ管理を行うためのツールが必要になります。
この手のいわゆるパッケージ管理ツールは gb や gom が有名のようですが、今回は試してみて便利だった glide を採用することにしました。
glide 使い方
glide コマンド自体をインストールします。
$ go get github.com/Masterminds/glide $ go install github.com/Masterminds/glide
glide コマンドで依存パッケージをインストールします。
$ glide create $ glide install
これで、対象ディレクトリに glide.yaml と glide.lock ができます。
また、vendor ディレクトリも作成され、その中に依存するパッケージが格納されます。
glide.yaml と glide.lock だけをリポジトリに格納して、vendor ディレクトリは Git で Ignore 指定してください。
このリポジトリを初めて使う方は、glide コマンド自体をインストールした後に glide install
をすれば、vendor ディレクトリに依存パッケージがインストールされます。
まとめ
私は普段 Ruby で開発をしていて Bundler を使っているのですが、 コマンド体系や構成ファイルがそれと似ており、違和感なく使うことができました。
もう一つの候補であった gom と比べると、コマンド体系や YAML 書式がスッキリしているのもイイ感じで、ドキュメントがよく整備されているのもあって、glide を正式導入することにしました。
逆に言えば、gom は Bundler によく似たコマンド体系や YAML 書式を持っているので、かなり複雑な設定もできそうです(Go 標準のツールがシンプルで強力なので複雑な設定自体が不要な気もしますが)。
glide や gom 以外のパッケージ管理を選択されるのも良いかと思いますが、現時点では glide が個人的に最もオススメできるパッケージ管理ツールです。
glide で快適な Go 開発を!
お知らせ
ねこじゃらしでは Go に限らず Ruby や JavaScript のプログラマ、UI/UX デザイナを募集しております。
ご興味をお持ちいただけましたら、以下のリンクからお問い合わせください。
開発部LTを開催しました! (テーマ Rack について)
バックアップ開発部の r-fujiwara です。 ねこじゃらし開発部では、二週間に一度、メンバーの最近の興味を持っていることや、業務で行っていることなどを持ち回りで LT を行っています。
今回
今回は記事を書いている r-fujiwara の番でした。 主に Rack(Application / Server) の話をさせて頂きました。
分かったつもりになるかもしれないRack
この発表をしようと考えた動機
(冒頭にもありますが、)教えている後輩に「Rack って何ですか?」と聞かれて答えに窮してしまったので、この機会にちょっと触れてみたかったから。
Rails
のDevelopment
で開発していると、やはり「WEBrickって何よ?」「Puma って何よ?」って所に関して、多分自分自身もあまり自信を持って答えられ無さそうだったので、この機会で整理したかったから。しかしながら、Rack のことをあまりにも普通に話しすぎてしまっても、それはそれで何かしらのドキュメントを読めばいい話であると考え、今回は「車で例える」というアプローチを取り、より噛み砕いた説明が出来ないか、と考えて今回の Rack の発表といたしました。
こういった背景があります。
個人的感想
自分としては rack は非常に面白い仕組みであり、Rack Server や Rack Application のソースを読むだけでもかなり力になる、と考えております。
アプリケーションを作るだけでなく、その中身がどう動いているのか?とちゃんと理解して然るべき技術選定出来るエンジニアになっていきたいと私は考えておりますし、またそういった人材をねこじゃらしで育てていければ、と考えております。
Go の標準っぽいプレゼンを作る - 完全版
バックアップ開発部の y-okubo と申します。
今回は、以下の記事で書いた内容の(ほぼ)完全版を書きます。
概要
- Go 界隈の方々がよく使っているプレゼンツール(フォーマット)です
- とは言えど、このツールを使っていないプレゼンもいっぱいあります
- 当然ですが Go で書かれています
- シンタックスハイライトは美しいですが、フォーマットの指定方法が特殊です
インストール
GOPATH を設定した上でインストールします
$ go get golang.org/x/tools/cmd/present
サーバ起動
作成するスライドを格納するディレクトリに移動してから実行します
$ present
デフォルトでは http://127.0.0.1:3999 にアクセスすることでプレゼンが見られるようになります。
フォーマット
プレゼンのメタ情報
Title of document Subtitle of document 15:04 2 Jan 2016 Tags: foo, bar, baz Author Name Job title, Company joe@example.com http://url/ @twitter_name * Title of slide or section (must have asterisk)
最低限、この内容(アスタリスクの部分)までないと表示できません(以外とハマります、コレ)。
- 一行目はプレゼンのタイトルです
- 二行目はプレゼンのサブタイトルです
- 三行目はプレゼンの発表日時?
- 四行目はタグ?ですかね(どこで役に立つのかは不明)
- 空行を挟んで個人プロフィール各種(名前・役職・会社名・メールアドレス等々)
- さらに空行を挟んで次のスライドタイトルになります
箇条書きとセクション
- bullets 1 - more bullets 1 - a bullet with 1
* Slide title or section ** Sub section *** More sub section
サブセクション以降はプレゼンの下から順に表示されます。
例えば
* Title of slide or section (must have asterisk) ** Subsection1 - bullets 2 - more bullets 2 - a bullet with 2 *** Subsubsection2 - bullets 1 - more bullets 1 - a bullet with 1
これは
こんな感じで表示されます(正直ちょっと違和感があります)。
テキスト
* Text Some More text Preformatted text is indented (however you like)
書いた内容がそのまま反映されます。
インデントを行うとその部分が整形済みテキスト(pre タグ)になります。
フォント
* Font _italic_ *bold* `program` _this_is_all_italic_ _Why_use_scoped__ptr_? Use plain ***ptr* instead.
上から順番に * イタリック * ボールド * プログラム? * イタリック * ボールド(先頭のアスタリスクもボールドにしたいのでエスケープしてる?)
こんな感じで表示されます。
インラインリンク
* Inline link [[url][label]], or [[url]]
ラベルを付けるか、そのままリンクを表示するかの違いですね。
リンク
* Link .link http://golang.org golang.org
Playground で直接実行可能な状態にする
* The Go Playground .play demo.go
こんな UI が付きます。
コード
コードは別ファイルの置く必要があります。
* Code .code -numbers test.go /START OMIT/,/END OMIT/
/開始箇所/,/終了箇所/
で表示するコードを指定します。
なお、正規表現が使えます。
イメージ
* Images .image gopher.png 408 300
高さと幅を指定できます。
公開する
http://go-talks.appspot.com で 動的に表示できます。
http://go-talks.appspot.com/github.com/owner/project/file.ext
という形式で指定すれば、作成したプレゼンが表示されます。
GitHub URL 途中の blob
や master
は 取り除いてください。
こちらは表示例です。
http://go-talks.appspot.com/github.com/y-okubo/go-present-example/sample.slide
まとめ
いかがでしょうか。
かなりクセのあるフォーマットで書きやすいとは言えないのですが、お、できるな!と思わせるプレゼンが作れるので、 Go のコミュニティで発表する予定の資料は present で、それ以外では普段お使いのプレゼンソフトを使われのが良いかと思います。
さらに詳細なフォーマットについては present の GoDoc をご覧ください。
お知らせ
ねこじゃらしでは Go に限らず Ruby や JavaScript のプログラマ、UI/UX デザイナを募集しております。
ご興味をお持ちいただけましたら、以下のリンクからお問い合わせください。
GlusterFS + Go の開発環境を Docker で構築
バックアップ開発部の y-okubo と申します。
今回は「gogfapi を使った簡単な API Server」を作るにあたり、Docker を使って Go の開発環境を構築した手順を紹介させていただきます。
「gogfapi を使った〜」は弊社が毎年行っている開発合宿のお題として選んだ物で(社内的にはもうちょっとクールなお題にしています)、そちらは別の機会に紹介したいと思います。
構成
開発環境なのでデータの永続化は考慮していません。
サーバ
当初は DockerHub でイメージを探したのですが、イメージを生成すると GlusterFS のインストールで失敗する事が多いので自作することにしました。
Dockerfile はこんな感じです(途中の root:password
はとても意識が低いので適宜書き換えてご利用ください)。
FROM centos ENV container docker # Install require packages RUN yum --setopt=tsflags=nodocs -y update RUN yum --setopt=tsflags=nodocs -y install wget nfs-utils openssh-server vim RUN yum -y swap -- remove fakesystemd -- install systemd systemd-libs # Added to enable systemd. Reference: http://developerblog.redhat.com/2014/05/05/running-systemd-within-docker-container/ RUN yum -y update; yum clean all; \ (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \ rm -f /lib/systemd/system/multi-user.target.wants/*;\ rm -f /etc/systemd/system/*.wants/*;\ rm -f /lib/systemd/system/local-fs.target.wants/*; \ rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ rm -f /lib/systemd/system/basic.target.wants/*;\ rm -f /lib/systemd/system/anaconda.target.wants/*; # Add epel repository RUN wget http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-6.noarch.rpm RUN rpm -ivh epel-release-7-6.noarch.rpm # Install GlusterFS packages RUN wget http://download.gluster.org/pub/gluster/glusterfs/3.7/LATEST/EPEL.repo/glusterfs-epel.repo -O /etc/yum.repos.d/glusterfs-epel.repo RUN yum -y update RUN yum --setopt=tsflags=nodocs --enablerepo=epel -y install glusterfs glusterfs-server glusterfs-fuse glusterfs-geo-replication glusterfs-cli glusterfs-api glusterfs-api-devel glusterfs-devel RUN yum --setopt=tsflags=nodocs --enablerepo=epel -y install attr iputils iproute RUN yum clean all RUN echo 'root:password' | chpasswd VOLUME [ “/sys/fs/cgroup” ] EXPOSE 111 245 443 24007 2049 8080 6010 6011 6012 38465 38466 38468 38469 49152 49153 49154 49156 49157 49158 49159 49160 49161 49162 RUN systemctl disable nfs-server.service RUN systemctl enable rpcbind.service RUN systemctl enable sshd.service RUN systemctl enable glusterd.service CMD ["/usr/sbin/init"] COPY ./startup.sh /var/startup.sh RUN chmod +x /var/startup.sh RUN echo /var/startup.sh >> /root/.bashrc
ポイントは
- EPEL レポジトリを追加
startup.sh
を実行
しているところでしょうか。
GlusterFS のインストールに失敗していたのが yum install
あたりだったので、自分で EPEL レポジトリを追加しています。
startup.sh
の内容についてはこの後に説明します。
その他の内容は GlusterFS official docker image を参考にしています。
startup.sh
の内容は以下になります。
#!/bin/bash # Create volume mkdir /var/gfs_srv_vol gluster peer probe $HOSTNAME gluster volume create gfs_volume $HOSTNAME:/var/gfs_srv_vol force gluster volume start gfs_volume gluster volume quota gfs_volume enable # Mount volume mkdir /var/gfs_cli_vol mount -t glusterfs -o acl $HOSTNAME:/gfs_volume /var/gfs_cli_vol
こちらでは GlusterFS のボリューム作成とローカルマウントを行っています。
Dockerfile の中の RUN
で実行したかったのですが、$HOSTNAME
環境変数を使いたかったのでシェルスクリプトで実行するようにしてあります。
クライアント側
サーバ側とほぼ一緒の Dockerfile になります(こちらも途中の root:password
はとても意識が低いので適宜書き換えてご利用ください)。
FROM centos ENV container docker # Install require packages RUN yum --setopt=tsflags=nodocs -y update RUN yum --setopt=tsflags=nodocs -y install wget nfs-utils openssh-server vim RUN yum -y swap -- remove fakesystemd -- install systemd systemd-libs # Added to enable systemd. Reference: http://developerblog.redhat.com/2014/05/05/running-systemd-within-docker-container/ RUN yum -y update; yum clean all; \ (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \ rm -f /lib/systemd/system/multi-user.target.wants/*;\ rm -f /etc/systemd/system/*.wants/*;\ rm -f /lib/systemd/system/local-fs.target.wants/*; \ rm -f /lib/systemd/system/sockets.target.wants/*udev*; \ rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \ rm -f /lib/systemd/system/basic.target.wants/*;\ rm -f /lib/systemd/system/anaconda.target.wants/*; # Add epel repository RUN wget http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-6.noarch.rpm RUN rpm -ivh epel-release-7-6.noarch.rpm # Install GlusterFS packages RUN wget http://download.gluster.org/pub/gluster/glusterfs/3.7/LATEST/EPEL.repo/glusterfs-epel.repo -O /etc/yum.repos.d/glusterfs-epel.repo RUN yum -y update RUN yum --setopt=tsflags=nodocs --enablerepo=epel -y install glusterfs glusterfs-fuse glusterfs-cli glusterfs-api glusterfs-api-devel glusterfs-devel RUN yum --setopt=tsflags=nodocs --enablerepo=epel -y install attr iputils iproute RUN yum clean all RUN echo 'root:password' | chpasswd VOLUME [ “/sys/fs/cgroup” ] EXPOSE 111 245 443 24007 2049 8080 6010 6011 6012 38465 38466 38468 38469 49152 49153 49154 49156 49157 49158 49159 49160 49161 49162 RUN systemctl disable nfs-server.service RUN systemctl enable rpcbind.service RUN systemctl enable sshd.service CMD ["/usr/sbin/init"] RUN yum --setopt=tsflags=nodocs -y groupinstall "Development Tools" RUN wget https://storage.googleapis.com/golang/go1.6.2.linux-amd64.tar.gz RUN tar -C /usr/local -xzf go1.6.2.linux-amd64.tar.gz COPY ./hello.c /root/hello.c RUN mkdir -p /root/go/bin \ && echo 'export GOROOT=/usr/local/go' >> /root/.bashrc \ && echo 'export GOPATH=/go/path' >> /root/.bashrc \ && echo 'export GOBIN=/go/bin' >> /root/.bashrc \ && echo 'export PATH=$PATH:$GOROOT/bin:$GOBIN' >> /root/.bashrc
こちらは最後の方で Go 開発環境のインストールと設定を行っています。
Go のソースコードはローカルマシン側に置いて、コンテナ起動時にマウントして参照できるようにしています。
イメージ生成
サーバ側
$ docker build -t glusterfs-server server
クライアント側
$ docker build -t glusterfs-client client
コンテナ起動
サーバ側
$ docker run --privileged -tid -p 20022:22 --hostname gfserver --name gfserver glusterfs-server
--privileged
で権限を与えて SELinux 等の影響を受けないようにしています。
クライアント側
$ docker run --privileged -tid -p 20023:22 -p 8080:8080 -v /Users/y-okubo:/go/path --link gfserver:server --hostname gfclient --name gfclient glusterfs-client
--link
で先ほど起動したコンテナを参照できるようにしてあります。
コンテナへ SSH ログイン
サーバ側
$ ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 20022 root@localhost
クライアント側
$ ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 20023 root@localhost
セキュリティ上よろしくないのですが、毎回 OpenSSH の警告が出るのを抑止しています。
クライアント→サーバの疎通確認(libgfapi 経由でのアクセス)
クライアント側に SSH ログインして、イメージ作成時に用意(Dockerfile にて指定)した hello.c
をビルド・実行します。
hello.c
のソースは以下になります。
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <glusterfs/api/glfs.h> int main (int argc, char** argv) { const char *gfserver = "server"; const char *gfvol = "gfs_volume"; int ret; glfs_t *fs; glfs_fd_t *fd; fs = glfs_new(gfvol); // Virtual filesystem type struct glfs_set_volfile_server (fs, "tcp", gfserver, 0); ret = glfs_init (fs); if (ret) { printf( "Failed to connect server/volume: %s/%s\n", gfserver, gfvol ); exit(ret); } char *greet = "Hello, Gluster!\n"; fd = glfs_creat(fs, "greeting.txt", O_RDWR, 0644); glfs_write(fd, greet, strlen(greet), 0); glfs_close(fd); return 0; }
$ gcc hello.c -lgfapi
$ ./a.out
まとめ
今回は GlusterFS の Go での開発環境を Docker で構築した際の流れを駆け足でご紹介しました。
今回はサーバ側でローカルマウントするようにしていますが、クライアント側でサーバ側のボリュームを FUSE マウントすれば別の用途でも使えるのではないかと考えています。
GlusterFS + Go という組み合わせにどれくらいの需要があるかは分かりませんが、何かのお役に立てれば幸いです。
お知らせ
ねこじゃらしでは Go に限らず Ruby や JavaScript のプログラマ、UI/UX デザイナを募集しております。
ご興味をお持ちいただけましたら、以下のリンクからお問い合わせください。
既存のiOSプロジェクトにUI自動テストを実装したの話
実装したアプリはWebAPIを使用したストレージアプリで、取得してきたデータをTableView(またはCollectionView)で表示する画面が複数あります。
開発人数は2名で別に品質管理チームがおり、品質管理チームにテストして貰う前に、UI自動テストを行うという目的です。
環境
- Xcode version 7.x
- KIF version 3.3.0
kif-framework/KIF: Keep It Functional - An iOS Functional Testing Framework
どこまでUIテストを行うか?
自動UIテストの範囲は広くどこまでやるかが明確ではないため、最終的に組み込まれたものと、そうではないものに分けて記載します。
自動テストしたこと
- シェルスクリプトを起動するだけすべてのUIテストが完了するようにする
- デバイスごと動作することを確認する(iPhoneとiPad)
- バージョンごとに動作することを確認する(iOS9とiOS8)
- ユーザー名、パスワードを入力してログインできる
- すべてのボタンが表示されていることを確認する
- すべてのボタンが動作されていることを確認する
- 検索が動作されていることを確認する
- アラートを表示は確認する
- TableViewに表示されている文字を確認する
- テスト中にスクリーンショットを保存する
複数デバイスで起動するためはxcodebuild
をシェルスクリプトで起動するようにする必要がありました。
UIテストは開発者視認できないほど早く動作し目視の確認が難しいため、テスト時にスクリーンショットを保存するのは有効です。 またスクリーンショットをフォルダ別にデバイス名、iOSバージョン、アプリバージョンを記載することで、バージョンごとの画面ログとして効果があります。
すべてのUIテストはファイルごと独立して動くようになっています、これはKIFでUIテストの順番を指定できないためです。
例えばLoginUITest.swift
とLogoutUITest.swift
があるときにLoginUITest.swift
が先にテストされるとは限りません。
そのためLoginUITest.swift
のはじめにログアウト処理、LogoutUITest.swift
がのはじめにログイン処理を入れてあります
自動テストしなかったこと
- ネットワークエラー時
- 画面数xネットワークエラー数は数が多くなりすぎる上にエラーテストとUIテストを同時にやるのは難しい
- ログイン時のユーザー名、パスワード入力のエラーケース
- 上記と同じくエラーケースが多いので、ほとんどやらなかった
- ユーザーが開発者が想定外の操作をするケース
- ボタンに対して連続タップをする、高速でスワイプをするなどのケース
- 操作後に正常であることを示すテストが難しかったため
- ボタンに対して連続タップをする、高速でスワイプをするなどのケース
例外処理時のテストを実装するにはかなり時間がかかり、ほとんど実装はしませんでした。
KIFで発生した問題
日本語のキーボードは無効にしておく
- 試験をしているとシミュレーターの入力モードが日本語になってしまうことがあったので、日本語入力にならないように設定を変更しました。
- シミュレーターのiOSのSettings > General > Keyboard > で Japanese-Kana を削除
連絡帳へのアクセスを許可しますか?
などのシステムアラートは検知できないことがあるtester.acknowledgeSystemAlert()
が動作しないことがあります- 解決法が無いですが、予めシステムの許可を設定するか、目視でタップする用にしていました
UIテストの起動に失敗する
エラーログも出ないことがあるxcodeを再起動することで、起動できたりもします
表示されているUIが検知できないでテストが失敗する
- XCTestでも発生する、現状で有効な回避方法はないと思います
実装後の感想
- 今のところスマホのUIテストにベストプラクティはないので、手探りでやるしかない
- 状態遷移が多いアプリはテスト作成に非常に時間がかかる
Unitテストと違い、UIテストを必須にすることは非常に難しい
メリット