TypeScript で `error TS2300: Duplicate identifier` がでたが yarn にしたら治った

npm ライブラリを install して tsc したらこんなエラーが大量に出た。

node_modules/@google-cloud/firestore/types/firestore.d.ts(28,15): error TS2300: Duplicate identifier 'DocumentData'.
node_modules/@google-cloud/firestore/types/firestore.d.ts(35,15): error TS2300: Duplicate identifier 'UpdateData'.
...略
node_modules/firebase-admin/node_modules/@google-cloud/firestore/types/firestore.d.ts(28,15): error TS2300: Duplicate identifier 'DocumentData'.
node_modules/firebase-admin/node_modules/@google-cloud/firestore/types/firestore.d.ts(35,15): error TS2300: Duplicate identifier 'UpdateData'.
...略

解決策を先に言うと npm から yarn に乗り換えたらこのエラーが出なくなった。

$ rm packege-lock.json
$ rm -rf node_modules
$ npm i -g yarn
$ yarn
$ yarn run build          # tsc する

これだけで解決した。

原因

依存関係が Duplicate してしまっていたぽい。

  • package.json
    • pring.ts
    • firebase-admin

みたいに @google-cloud/firestore が2箇所から呼ばれて、それを npm がうまく解決できずどちらも install してしまい、その中に型定義があるため型定義が2回呼ばれて Duplicate identifier になっていたっぽい。

社の若者に「そのエラーつらそうだけど yarn にしたら治りそう」という助言をもらって yarn にしたら解決した。
yarn の方が賢いっぽい。

JavaScript でテストを書く時のライブラリについて調べた

1年半前は 業務 とか 趣味 で TypeScript を使ってテストも書いてたんだけど、最近は iOS ばかりで忘れてしまっていた。

けどまた仕事で同じような環境を作ったので、テストを書くときにどういう Framework があって役割は何かをメモっておく。

テストフレームワーク

テストを書くために必要なライブラリ。
iOS でいったら Quick や XCTest, Rails でいったら rspec とかが該当する。

アサーションライブラリ

iOS でいうと Nimble が該当する。
XCTest や rspec には組み込みで入っている。

mock / stub / spy

sinon 以外に話題に上がっているのを見なかったので、デファクトスタンダードだと思っていいのかもしれない。

テストランナー

コマンドラインでテスト実行したらブラウザが開いて〜みたいなのができるっぽい。

用途に合わせて構成を決める

自分はモックやテストランナーは不要だけど TypeScript を使っているので mocha + power-assert + espower-typescript という構成になった。
今後モックしたくなったら sinon を追加すると思う。

ReactNative とかでがっつりテスト書くなら jest は良さそうだし、ブラウザでテストをするなら Karma などが必要かもしれない。
その辺は人によって違うので各自選ばないといけない。

参考

USUM が発売されてから、ダメージ計算Zアプリではどのようなポケモン・技がよく計算されているのか

adventar.org

Pokémon RNG Advent Calendar 2017 13日目です!

2017年11月17日にポケットモンスター ウルトラサン・ウルトラムーンが発売されてからもうすぐ1ヶ月が経とうとしています。

私が開発しているダメージ計算Zという iOS アプリは11月20日に USUM に対応しました。

ダメージ計算Z for ポケモン ウルトラサンムーン

ダメージ計算Z for ポケモン ウルトラサンムーン

  • Kensuke Hoshikawa
  • ユーティリティ
  • 無料

このアプリでは、どのようなポケモンや技などで計算したのかというデータを持っています。
そのデータを見ながら、どのようなポケモンがダメージ計算対象となっているのかを見ていこうと思います。

PGL

ダメ計Z のデータを見る前に、 PGLポケモンランキングを見てみましょう。

f:id:star__hoshi:20171213183342p:plain

https://3ds.pokemon-gl.com/battle/usum/

  1. ミミッキュ
  2. ランドロス(霊獣)
  3. リザードン
  4. カプ・コケコ
  5. カプ・テテフ
  6. カプ・レヒレ
  7. メタグロス
  8. ギャラドス
  9. アーゴヨン
  10. バシャーモ
  11. カバルドン

という順位になっています。

攻撃側のポケモン

では、ダメ計Z でよく計算されているポケモンを見てみましょう。

# ポケモン 割合
1 ミミッキュ 7.59%
2 カプ・テテフ 4.96%
3 アーゴヨン 4.48%
4 カプ・コケコ 4.36%
5 メガボーマンダ 3.54%
6 メガバシャーモ 2.97%
7 ランドロス(霊獣) 2.92%
8 メガルカリオ 2.84%
9 メガリザードンY 2.75%
10 ゲッコウガ 2.35%
11 ボルトロス(霊獣) 2.13%
12 メガメタグロス 2.01%
13 メガギャラドス 2.01%
14 メガリザードンX 1.73%
15 ギルガルド(ブレード) 1.48%

という順番になりました。
ミミッキュがダントツですが、新規ポケモンとしてはアーゴヨンが3位にランクインしています。

メガ系が多くランクインしていますが、メガ後とメガ前は別々の集計になっているので合計したらもっと上にきそうです。

防御側のポケモン

次に、防御側としてよく計算されるポケモンです。

# ポケモン 割合
1 ミミッキュ 5.12%
2 ランドロス(霊獣) 4.81%
3 メガボーマンダ 4.26%
4 カバルドン 3.57%
5 カプ・コケコ 2.93%
6 アーゴヨン 2.68%
7 カプ・レヒレ 2.68%
8 カプ・テテフ 2.57%
9 メガリザードンY 2.45%
10 ポリゴン2 2.37%
11 メガメタグロス 2.31%
12 ナットレイ 2.26%
13 ギルガルド(シールド) 2.22%
14 テッカグヤ 2.14%
15 ガブリアス 2.06%

ミミッキュが1番なのは変わりませんが、割合はダントツというほどではありません。

攻撃側では出てこなかったカバルドンポリゴン2ナットレイがランクインしており、やはり受けとして優秀なポケモンが多く見られます。
また、メガボーマンダは攻撃側よりも防御側で多く計算されているようです。

ポケ管理で作成されているポケモン

ダメ計Z にはポケ管理という機能があり、自分が育成したポケモンのメモやよく使う仮想敵の登録などができる機能があります。
そのランキングを見てみましょう。

# ポケモン 割合
1 ミミッキュ 8.17%
2 カプ・テテフ 5.13%
3 アーゴヨン 3.92%
4 カプ・コケコ 3.03%
5 ルカリオ 2.66%
6 メガリザードンY 2.34%
7 ボルトロス(霊獣) 2.28%
8 ゲッコウガ 2.27%
9 ランドロス(霊獣) 2.25%
10 メガボーマンダ 2.17%
11 メガメタグロス 1.99%
12 ガブリアス 1.95%
13 メガバシャーモ 1.67%
14 ギャラドス 1.62%
15 メガクチート 1.60%

攻撃側、防御側で出てきたポケモンが並んでいます。

今まで出てこなかったクチートが出てきていたり、ギャラドスだけメガじゃなかったりしますが、特に変わったデータはないですね。

最後に、どのような技で計算されているかです。

# 割合
1 じしん 4.20%
2 じゃれつく 3.53%
3 10まんボルト 3.35%
4 サイコキネシス 3.10%
5 めざめるパワー(こおり) 2.33%
6 シャドーボール 2.29%
7 れいとうビーム 2.24%
8 フレアドライブ 2.05%
9 りゅうせいぐん 2.03%
10 シャドークロー 1.99%
11 かげうち 1.98%
12 だいもんじ 1.81%
13 すてみタックル 1.70%
14 アイアンヘッド 1.62%
15 ムーンフォース 1.60%

概ね想定通りですが、やはり対戦でよく見る技が多いです。
Z技が一つも入っていないのは、Z技変換ボタンを使用した時の集計ができていないからです...。そのデータもとっておけばよかった...。

おわり

PGL の上位ポケモンとほぼ同じポケモンがダメージ計算アプリでも使われています。
ですが PGL では26位だったルカリオがアプリではよく利用されていたり、ガブリアスの時代は終わってミミッキュの時代になったんだな... ということがわかりました。

アプリ起動時の初回済みのポケモンガブリアスでなくミミッキュにするべきということがわかりました、近いうちに更新しようと思います。

ダメージ計算Z for ポケモン ウルトラサンムーン

ダメージ計算Z for ポケモン ウルトラサンムーン

  • Kensuke Hoshikawa
  • ユーティリティ
  • 無料

iPhone を使っていてまだダメージ計算Zを使っていない人はダウンロードして見てください 🤗

PlantUML でシーケンス図を書いたがめっちゃ良かった

PlantUML

シンプルなテキストファイルで UML を作ることのできる、オープンソースのツール

今までは astah とかでユースケース図とかシーケンス図書いてたんだけど、 GUI で書くの辛いなと思って PlantUML というのを使ってみた。

コードで UML を書ける、今回はシーケンス図を書いたけどユースケース図やフローチャートなども書ける。

環境構築

Web のエディタだと PlantUML Editor というのがある。

けどローカルでやりたかったので VSCode の拡張を入れた。

marketplace.visualstudio.com

これを入れるだけ、シンタックスも効くようになって良い。
Java, Graphviz などを入れておけとあるけど、特に何もせず使えているので別アプリケーション経由でインストールされてたのかもしれない。

拡張子は .pu, .plantuml, .wsd などあるっぽいが .pu にしている。

書いてみる

記法

今回自分が使ったやつだけ。
シーケンス図の構文と機能 に網羅的に書いてあるけど多すぎて使いこなせていない。

  • 登場人物の宣言
    • 表示形式や表示順などを最初に定義できる
      • actor Hoge
      • database Fuga
  • 矢印
    • -> は直線、 --> は破線
    • Hoge -> Fuga: description
    • Fuga --> Huga
  • 動作中を示す表示
    • activate, deactivate で動作中を示せる
      • activate Hoge
      • deactivate Fuga
  • メモ
    • note, hnote でメモが書ける
    • note は四角、 hnote はひし形
    • left of, right of, over で位置を指定できる
      • note left of Hoge: desc
      • note right of Fuga
      • note over Hoge
  • タイトル
    • == で文字を囲むとタイトルになる
        • == タイトル ==

この 5 つの要素を覚えるだけでいいシーケンス図がかけた。

サンプル

@startuml

actor GameManager
database Application
database Database
actor User

== マスタデータ更新 ==

GameManager -> Application: データ登録
activate GameManager
activate Application

note over GameManager: 処理中は画面操作できない

Application -> Database: Insert
activate Database

Database --> Application: Success
deactivate Database

Application -> Application: データ加工

note right of Application #aqua
攻撃力↑↑
end note

Application -> Database: Insert
activate Database

Database --> Application: Success
deactivate Database

Application --> GameManager: Complete
deactivate Application
deactivate GameManager

== データ表示 ==

User -> Application: データ取得
activate User
activate Application

hnote over User : 読み込み待ち

Application -> Database: select * from item
activate Database

Database --> Application: result
deactivate Database

Application -> Application: jsonize

Application --> User: render json
deactivate User
deactivate Application

@enduml

f:id:star__hoshi:20171208181929p:plain

プログラミングでポケモンのダメージ計算をしてみよう

adventar.org

Pokémon RNG Advent Calendar 2017 7日目です。
昨日は ポケモンの実数値や努力値をプログラミングで計算 するという内容を書きました。
今日はダメージ計算をしてみようと思います。

この記事はプログラミングがわからない人には難しい内容ですが、ダメージ計算アプリがどういう苦しみを経てあの計算結果を算出しているかが少しでも伝わればいいと思っています。
プログラムが長々と書かれているところは読み飛ばして、最後のところだけ読んでもらっても構いません 🙏

ダメージ計算してみる

ダメージは以下の計算式で求めることができます。

{(攻撃側のレベル × 2 ÷ 5 + 2)× 技の威力 × 攻撃側の能力値 ÷ 防御側の能力値 ÷ 50 + 2}×乱数(85~100)÷ 100 ×タイプ一致×タイプ相性1×タイプ相性2
ダメージ計算と実数値【マンキーでもわかるポケモン講座】 - ポケモンORASのトリセツ

ただの四則演算ですね。紙に書いて、丁寧に値を当てはめれば計算できそうです。
これをプログラムに落とし込んでいきましょう、 Swift というプログラミング言語です。

// (攻撃側のレベル × 2 ÷ 5 + 2)
let level = floorf((Float(攻撃側のレベル * 2) / 5.0) + 2.0)

// { level × 技の威力 × 攻撃側の能力値 ÷ 防御側の能力値 ÷ 50 + 2}
let baseDamage = floorf(
    floorf(
        (level * 技の威力 * 攻撃側の能力値) / 防御側の能力値
    ) / 50
) + 2.0

// baseDamage × 乱数(85~100)÷ 100 ×タイプ一致×タイプ相性1×タイプ相性2
var damages: [Int] = []
for i in 0...15 {
    var damage: Float = floorf(baseDamage * Float(85 + i) / 100.0)

    if タイプ一致攻撃 {
        damage = 五捨六入(damage * 1.5)
    }

    // タイプ相性は割愛 (今回のダメージ計算では使わないため)

    damages.append(Int(damage))
}

難しいかもしれないですが、よくみるとなんとなく理解できると思います。
レベルの計算をして、基本ダメージの計算をして、乱数を 0.85~1.00 、タイプ相性を計算という流れになっています。

パラメータを埋め込んでみる

上記の計算式に実際に数値を埋め込んでみましょう。
ピカチュウがメガトンパンチをメガガルーラに打つ、というケースで考えてみます。

let 攻撃側のレベル = 50
let 技の威力: Float = 80
let 攻撃側の能力値: Float = 75
let 防御側の能力値: Float = 120
let タイプ一致 = false

let level = floorf((Float(攻撃側のレベル * 2) / 5.0) + 2.0)
let baseDamage = floorf(
    floorf(
        (level * 技の威力 * 攻撃側の能力値) / 防御側の能力値
    ) / 50
) + 2.0

var damages: [Int] = []
for i in 0...15 {
    var damage: Float = floorf(baseDamage * Float(85 + i) / 100.0)

    if タイプ一致 { // タイプ不一致
        damage = 五捨六入(damage * 1.5)
    }

    damages.append(Int(damage))
}

print(damages)
// => [20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24]

計算結果が 20~24 になりました。
ダメージ計算Z での計算結果を見てみると、見事一致しています。

f:id:star__hoshi:20171207024614p:plain

これで一般的なダメージ計算はできるようになりました 👏

おやこあいに対応してみる

次は特性: おやこあいに対応してみましょう。

おやこあいの仕様として

  • 2回攻撃
  • 2回目はダメージが 0.25 倍される

という 2 つの要素があります。
この要素をプログラムに落とし込む必要があります。

func calc(count: Int) -> [Int] {
    let 攻撃側のレベル = 50
    let 技の威力: Float = 80
    let 攻撃側の能力値: Float = 145
    let 防御側の能力値: Float = 60
    let タイプ一致 = true
    let おやこあい = true

    let level = floorf((Float(攻撃側のレベル * 2) / 5.0) + 2.0)
    let baseDamage = floorf(
        floorf(
            (level * 技の威力 * 攻撃側の能力値) / 防御側の能力値
            ) / 50
        ) + 2.0

    var damages: [Int] = []
    for i in 0...15 {
        var damage: Float = floorf(baseDamage * Float(85 + i) / 100.0)

        if タイプ一致 { // タイプ一致
            damage = 五捨六入(damage * 1.5)
        }

        if おやこあい && count == 2 {
            damage = 五捨六入(damage * 0.25)
        }

        damages.append(Int(damage))
    }

    return damages
}

var damages = calc(count: 1)
let parentalBondDamages = calc(count: 2)
// 2 つの計算結果を合計する
for (i, d) in parentalBondDamages.enumerated() {
    damages[i] += d
}
print(damages)
// => [136, 139, 140, 142, 144, 146, 147, 150, 150, 151, 154, 155, 157, 159, 161, 162]

同じ計算処理を2回しないといけないので、 func という関数を利用して再利用できるようにしています。
この関数を2回実行して、2回目はダメージを0.25倍しています。

計算結果は 136 ~ 162 と出ました。これもダメージ計算Zと一致していますね。

f:id:star__hoshi:20171207024555p:plain

おやこあいグロウパンチに対応する

次はグロウパンチの要素を入れて考えてみましょう。
グロウパンチ

  • 2回目のダメージ計算の時にはランク補正が1上昇する

という仕様が追加されます。これに対応できるようにしましょう。

func calc(count: Int) -> [Int] {
    let 攻撃側のレベル = 50
    let 攻撃側の能力値: Float = 145
    let 防御側の能力値: Float = 60
    let タイプ一致 = false
    let グロウパンチ = true
    let おやこあい = true
    let 技の威力: Float
    if おやこあい && グロウパンチ && count == 2 {
        技の威力 = 40 * 1.5
    } else {
        技の威力 = 40
    }

    let level = floorf((Float(攻撃側のレベル * 2) / 5.0) + 2.0)
    let baseDamage = floorf(
        floorf(
            (level * 技の威力 * 攻撃側の能力値) / 防御側の能力値
        ) / 50
    ) + 2.0

    var damages: [Int] = []
    for i in 0...15 {
        var damage: Float = floorf(baseDamage * Float(85 + i) / 100.0)

        if タイプ一致 { // タイプ不一致
            damage = 五捨六入(damage * 1.5)
        }

        if おやこあい && count == 2 {
            damage = 五捨六入(damage * 0.25)
        }

        damages.append(Int(damage))
    }

    return damages
}

var damages = calc(count: 1)
let parentalBondDamages = calc(count: 2)
for (i, d) in parentalBondDamages.enumerated() {
    damages[i] += d
}
print(damages)
// => [51, 51, 52, 52, 53, 53, 55, 55, 55, 56, 56, 57, 58, 59, 59, 60]

どんどん複雑になっていきますね。
おやこあい + グロウパンチ + 2回目の時だけ技の威力が 1.5 倍されるようになりました。

ダメージ計算Z とも一致しています。

f:id:star__hoshi:20171207024537p:plain

おわり

今回は「おやこあいグロウパンチ」に特化したダメージ計算式をプログラムで書きました。

おやこあいの対応ですらプログラムは複雑です。
実際のポケモン対戦では特性はポケモンによって違うし、テクニシャンで技の威力が60以下だったら... というような分岐が大量に発生していくことになります。

特性や技、道具、ポケモンによる条件の違いなどを1つ1つ真心をこめて定義しているのがダメージ計算アプリです。
これらの条件を意識しつつ人間が計算するのはかなり難しいので、ポケモン廃人の皆さんはアプリを使って効率的にダメージ計算を行いましょう。

ダメージ計算Z for ポケモン ウルトラサンムーン

ダメージ計算Z for ポケモン ウルトラサンムーン

  • Kensuke Hoshikawa
  • ユーティリティ
  • 無料

もっと興味がある人は

このライブラリで抽象的なダメージ計算ができるようになっています。

github.com

let pikachu = ...
let メガガルーラ = ...
let battle = Battle(attackPokemon: pikachu, defensePokemon: メガガルーラ)
print(battle.calculate())

未実装のものも多いですが、これだけでダメージ計算ができます 💪

ポケモンの実数値や努力値をプログラミングで計算してみよう

adventar.org

Pokémon RNG Advent Calendar 2017 6日目です!
乱数の話ではありませんが、ポケモンの実数値, 努力値をプログラミングで計算する話をします。

この記事は、

  • プログラムに興味あるポケモン好きな人
  • ダメージ計算などで実数値の調整をしてるけど実際にどうやって計算しているのかわからない人

になんとなく理解してもらえたらなと思います。

はじめに

ポケモンには3値(種族値個体値努力値)がありますが、これらの解説はしません。
この3値を使って実数値を算出していきます。

数値計算

ポケモン徹底攻略 にわかりやすく実数値の計算方法が書いています。

HP
能力値=(種族値×2+個体値努力値÷4)×レベル÷100+レベル+10

HP以外の能力
能力値={(種族値×2+個体値努力値÷4)×レベル÷100+5}×性格補正

特に難しくないですね、単なる四則演算です。
これを Swift というプログラミング言語で書くとこのようになります。

HP

let hp種族値 = 100
let hp個体値 = 31
let hp努力値 = 0
let level = 50

let temp1 = Float((hp種族値 * 2) + hp個体値 + (hp努力値 / 4))
let temp2 = temp1 * (Float(level) / 100)
let hp = Int(temp2) + level + 10

ちょっと複雑になってしまいました、Int と Float という概念が入ってくるとややこしいですね。
整数と小数点で扱いが違うので、プログラム上はそれらを意識しなければなりません。

レベル÷100 のところでが、 50÷100 の場合整数だと切り捨てられて0になってしまいますが、小数点だと0.5になります。
なので Float という小数点を扱える型に変換してから計算しています。

HP以外の能力

let 攻撃種族値 = 100
let 攻撃個体値 = 31
let 攻撃努力値 = 0
let 性格補正: Float = 1.0
let level = 50

let temp1 = Float((攻撃種族値 * 2) + 攻撃個体値 + (攻撃努力値 / 4))
let temp2 = temp1 * (Float(level) / 100)
let temp3 = Int(temp2) + 5
let 攻撃 = Int(Float(temp3) * 性格補正)

HP と似ていますがちょっとだけ違いますね、大きな違いとして、性格補正の計算が入ってきました。
やはり整数<->小数点の型変換があって難しく見えますが、やっていることは HP と同じ四則演算です。

努力値を算出してみよう

さて、種族値個体値努力値を使って 実数値 を割り出すことができました。
今度は種族値個体値・実数値の3つを使って 努力値 を算出してみましょう。

HP

種族値が100, 個体値が31, 実数値が 200 の場合、努力値は幾つになるかを求めてみます。

let hp種族値 = 100
let hp個体値 = 31
let hp実数値 = 200
let level = 50

for hp努力値 in 0...252 {
    let temp1 = Float((hp種族値 * 2) + hp個体値 + (hp努力値 / 4))
    let temp2 = temp1 * (Float(level) / 100)
    let tempHp実数値 = Int(temp2) + level + 10
    if hp実数値 == tempHp実数値 {
        print(hp努力値)
        break
    }
}

for というものが入ってきました。これは繰り返しを表すもので、 0 ~ 252 を1つずつ増やして実行し続けます、ループなどとも呼ばれます。
for の中をみてみると、先ほど HP の実数値を求めた式と同じものが書かれています。

努力値を求めるというのは実は単純で、努力値が0の場合の実数値を求め、努力値が1の場合の実数値を求め... というのを繰り返します。
そしてその実数値が 200 になった時、求めていた努力値を計算できたことになります。

今回でいうと努力値196 というのが算出されます。

HP以外の努力値個体値も今まで解説したのと同じ方法で取得できます。気になる人は考えてみましょう。

わざわざこんな計算したくないよね

個体値ずかんZ for ポケモン ウルトラサンムーン

個体値ずかんZ for ポケモン ウルトラサンムーン

  • Kensuke Hoshikawa
  • ユーティリティ
  • 無料

はい、便利なアプリがあるので使いましょう。

もっと深く知りたい人は

github.com

上記で解説したプログラムをもっと抽象的にしたライブラリがあります。
こんな感じでステータスをセットするとだけで計算ができるようになっていますので、興味がある人は覗いてみてください。

let name = "ミュウ"
let baseStats = BaseStats(hp: 100, attack: 100, defense: 100, specialAttack: 100, specialDefense: 100, speed: 100)
let effortValues = EffortValues(hp: 0, attack: 0, defense: 0, specialAttack: 0, specialDefense: 0, speed: 0)
let individualValues = IndividualValues(hp: 31, attack: 31, defense: 31, specialAttack: 31, specialDefense: 31, speed: 31)
let nature: Nature = .calm

let pokemon = Pokemon(name: name, baseStats: baseStats, effortValues: effortValues, individualValues: individualValues, nature: nature)
print("hp: ", pokemon.hp) // hp:  120
print("attack: ", pokemon.attack) // attack:  108

iOS Test Night #6 1周年 まとめ #ios_test_night

testnight.connpass.com

iOS Test Night #6 にブログ枠として参加したので、そのレポートです。 ㊗️ 1周年 🎉

開始前の挨拶として、Qiita に投稿された iOS のテスト関連の記事がこの一年で増えたのか? という話から始まりました。
結果として、増えはしたけどそこまで増えていないということで、今後も勉強会を通して iOS のテストをもっと盛り上げていくぞ 💪 とのことでした。

発表

Appiumで行う対話的テスト by @alligator_tama

TODO: 公開されたら資料はる

Appium で 2 つのアプリを立ち上げて、それらのアプリを対話的に実行させテストを行う、という内容。
Xcode9 から iOS Simulator が複数立ち上げられるようになってできるようになり、Appium の実行時に Port 番号を指定するだけで複数 Simulator を立ち上げることができる。

実際に 2 つのアプリが連携するデモが行われました。

Quick / Nimble をより快適に使うために by @tobi462

  • Quick / Nimble をライブコーディングを交えながら快適に使うはなし
    • Quick の概要や rspec のように構造的なテストにかけることのメリットの話や、 assertion ライブラリの Nimble についての話。
    • Nimble は英文のように読めるし、エラーメッセージもわかりやすく出力されるというメリットがある。
  • しかしメリットだけではなくデメリットもあって
    • 学習コストがかかる、ドキュメントの量も結構ある
    • BDD フレームワークの慣れが必要
    • 補完が微妙
      • Quick の expect ではなく XCTest の expect が出てきてしまったり、メソッドチェーンが切れると補完が効かない
  • これらのデメリットはラッパーを作ったり、スニペットを作って補完を改善できた。

fastlane snapshotの並列実行についてまとめた by @tarappo

fastlane snapshot の速度改善のはなし。

snapshot は指定端末・言語でスクショを簡単に取ることができるもの。snapshot は端末数・言語数が増えるほど実行時間が増加する。
今までの改善策はマシン3台用意するなど、金で殴っていた。

しかし Xcode9 から Simulator の並列実行ができるようになった、snapshot の設定を concurrent_simulators: true にするだけで良い。端末は devices で指定する。

MacPro (6コア) で並列実行した結果、5台同時起動する場合は 2 倍早くなったのでとりあえず並列実行するのが良さそう。

LT枠

assertion を積極的に使って役だった話 by @kboy_silvergym

筋肉 (assertion) の話。

  • assertion はわざとクラッシュさせること。
  • Assert, precondition, fatalError などがある。
  • assertion する目的は、実装漏れを防ぎたい、不安なところに念のため書いておく。
  • 実装もれを防ぐ
    • id == 0 だったらおかしい!
    • enum で絶対に通らないであろうところに assertionFailure()
  • 実際に防げた
    • サーバから uid というパラメータをサーバからもらえなかったことに気がつけた

未来のエンジニアのために assertion を残すというのはとても良さそう。

iOSシミュレータでのUIテストの様子を録画してみよう by @Kesin11

  • UITest は時間がかかるのと、テストが落ちた時にスクショを撮ってくれるけどなんでテストが落ちたのかわからない…。
    • なのでスクショじゃなくて録画したい。
  • QuickTime
    • コマンドからできないし不便
  • recordVideo

Test Nightきっかけでテストをはじめた人の発表枠

Mocking With Firebase by @d_date

TODO: 資料公開されたらはる

Firebase Realtime DB のテストについての話。

  • ターゲットで読み込むファイルを変えることでモック化する。
  • インターフェイスを同じにして処理を変えてテストをする。

プロジェクトの1ファイルにテストを書いてみた! 〜本当にこれで合ってるの…??〜 by @takattata

XCTest で CleanArchitecture のテストをかいてみたり、Firebase をモックしたり、RxSwift でテストを書いてみたけど本当に正しいのかわからんのであとでみんなに教えてほしい、みたいな感じだった。

何故テストが書けないのか by @fromkk

techblog.timers-inc.com

個人アプリなのでテストは書いてない。というかそもそもテストをかける設計になっていない。
なので設計を見直して適切に継承するようにした。

(自分の個人アプリもシングルトン + FatViewController + Realm + ノーテストなので心が痛かった... )