20190301のKotlinに関する記事は3件です。

[Flutter] Kotlin/Swift/C/C++ をモックせずにテストする

基本的にはできない/しない もの

Flutter では、3種類の Test を書くことでコードの品質を保つことができる。
そのうち、実機/エミュを使って実行されるのが Integration Test
このテストは、目/スクリーン の感覚で品質をテストするものであり、これを書く時 platform 依存のロジックは setMockMethodCallHandler を使ってモックするのが基本です。

じゃあどうするか?

Integration Test は実機/エミュで実行されるため、 platform 依存のメソッドを呼び出すことは可能。

ただし、Integration Test の test 側のファイルでは、アプリの使用するファイルを import することはできない。
そこで、Test 用 Widget を生成する側のファイルにテストしたい処理を挿し込むことで実現しました。

分かりにくいと思うので例を見て下さい。

例えば、 C/C++ で実装したロジックを Kotlin/Swift でラップし、さらにそれを Dart でラップした OthelloEngine クラスがあるとします。
それのロジックを モックせずにテストしたい ということ。

Test 用 Widget を生成する側のファイル に処理を挿し込む。こんな感じ。

test_driver/main.dart
// import 文は省略

void main() {
  // See: https://flutter.io/testing/ for more info.
  enableFlutterDriverExtension();

  // ***これを追加***
  othelloEngineTest();

  runApp(
     // Widget のあれこれ
  );
}

// platform 依存のロジックを含む処理
void othelloEngineTest() {
  final othelloEngine = OthelloEngine()
    ..echo()
    ..initialize()
    ..play('f5f6')
    ..move('f7')
    ..getDisc(0).then((disc) {
    if (disc != 5) {
        exit(0); // やべー
    }
  });
}

test_driver/main_test.dart
// import 文は省略

void main() {
  group('foo bar test', () {
    FlutterDriver driver;

    setUpAll(() async {
      driver = await FlutterDriver.connect();
    });

    tearDownAll(() async {
      if (driver != null) {
        await driver.close();
      }
    });

    test('foo bar ; verify foo bar',
        () async {
      // 色々テスト
    });
  });
}

そんで、こんな感じのコマンドで実行すれば OK

$ flutter drive --target=test_driver/main.dart --flavor=development

おわりに

しょうがないのかなぁ。。。と思っています。
Swift/Kotlin のレイヤーでテスト書いてもいいんですが、それをラップした Dart レイヤーでテストしたいってなりますよね....

ちなみに、Kotlin/C/C++ のデバッグ方法は この記事 にまとめておきました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Kotlinで美しきFizzBuzzを書く

Kotlinにも拘わらず、Javaと同じようにFizzBuzzを解くプログラムをあるブログで見ました
というわけでKotlinの言語機能を活かして美しきFizzBuzzを書いて見たいと思います
ただ、StringBuilderありとなしで結構変わるので今回は2つに場合分けして教えたいと思います

Kotlinらしくないコード(StringBuilderを使わない場合)

fun main(args: Array<String>) {
    for (num in 0..100) {
        if (num % 15 == 0)
            println("FizzBuzz")
        else if (num % 3 == 0)
            println("Fizz")
        else if (num % 5 == 0)
            println("Buzz")
        else
            println(num)
    }
}

引数を取らない場合はargs: Array<String>を省略できる

fun main() {
    for (num in 1..100) {
        if (num % 15 == 0)
            println("FizzBuzz")
        else if (num % 3 == 0)
            println("Fizz")
        else if (num % 5 == 0)
            println("Buzz")
        else
            println(num)
    }
}

これは多分殆どの人が知ってると思います

if文をExpressionとして使う

fun main() {
    for (num in 1..100) {
        println(
            if (num % 15 == 0) "FizzBuzz"
            else if (num % 3 == 0) "Fizz"
            else if (num % 5 == 0) "Buzz"
            else num
        )
    }
}

これはあまり綺麗ではありませんが、Kotlinでの必須テクであるので一応載せました
後述するwhen文と合わせるともうすこし綺麗にできます

when文を使う

fun main() {
    for (num in 1..100) {
        when {
            num % 15 == 0 -> println("FizzBuzz")
            num % 3 == 0 -> println("Fizz")
            num % 5 == 0 -> println("Buzz")
            else -> println(num)
        }
    }
}

見た目の美しさが全然違う!
やっぱりif...else-if...を延々と書かなくて済むのは楽ですね。ただしif...if...は作れないので注意です。

fun main() {
    for (num in 1..100) {
        println(
            when {
                num % 15 == 0 -> "FizzBuzz"
                num % 3 == 0 -> "Fizz"
                num % 5 == 0 -> "Buzz"
                else -> num
            }
        )
    }
}

ちなみにwhen文もExpressionとして利用可能です
まあ、正直さっきのほうが見やすい気もしますが一応

Kotlinらしくないコード(StringBuilderを使う場合)

fun main() {
    for (num in 1..100) {
        val builder = StringBuilder()
        if(num % 3 == 0) builder.append("Fizz")
        if(num % 5 == 0) builder.append("Buzz")
        if(builder.isEmpty()) builder.append(num)
        println(builder)
    }
}

buildString関数を使う

fun main() {
    for (num in 1..100) {
        println(buildString {
            if (num % 3 == 0) append("Fizz")
            if (num % 3 == 0) append("Buzz")
            if (isEmpty()) append(num)
        })
    }
}

buildString関数めっちゃ便利です。どんなプログラムでもよく使います
でもこれだとbuildStringがprintln関数の引数と使われているので、}の後に)があるのが少しきたないですね

forEachを使って書き換える

fun main() {
    (1..100).map {
        buildString {
            if (it % 3 == 0) append("Fizz")
            if (it % 5 == 0) append("Buzz")
            if (isEmpty()) append(it)
        }
    }.forEach(::println)
}

今までに書いてきた1..100の実体はIntRangeです。これとfor文を組み合わせるのが最も一般的ですが、StreamAPIとその拡張をつかってモダンに書くこともできます
ちなみに::printlnはメソッド参照です。メソッドの引数が要求される引数と一致するときに使うことができます。これ以外のメソッド参照の使い方としては、例えばJavaの一部ライブラリとかだとクラスを要求されることがあるので、そういう時KotlinではSomeClass.classとはできないのでSomeClass::class.javaとします
余談ですが、プロパティを読み込むときとかは

val properties = Properties()
val file = File(filePath)
file.inputStream().use(properties::load)

みたいにすると三行で読み込むことができます。便利!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ProgressTimeLatchとは何なのか

DroidKaigiのカンファレンスアプリのソースコードを見ていたら、 ProgressTimeLatch なるものが使われており、何だろうと思い調べてみると、色々と便利なやつだったので投稿します。

端的にいうと、プログレスバーなどを使っている時に起こるチラつきを、いい感じに制御してくれるやつでした。

ProgressTimeLatchとは

調べてみると、下記のツイートで紹介されたのが最初のようです。(おそらく)
Chris Banes氏と言えば、色々ライブラリを公開されており、お世話になった方も多いのではないかと思います。
https://twitter.com/chrisbanes/status/927928428539580416

ここで ContentLoadingProgressBar なるもの出てきますが、そもそも ProgressTimeLatchContentLoadingProgressBar の機能をどんなViewでも手軽に使えるように作られたもののようです。

ちなみに ContentLoadingProgressBar はSupport Libraryに入っているらしいです。(知らなかった…)
https://developer.android.com/reference/android/support/v4/widget/ContentLoadingProgressBar

どう便利なのか

アプリを作っていると、下記のようなことがあるかと思います。

  1. API通信などの非同期処理をする。
  2. 処理をしている間は、プログレスバーなどを表示して、処理中を表す。
  3. 処理が終了したら、プログレスバーなどを非表示にする。

あるあるの処理だと思います。

しかしながら、この処理の小さな問題として、APIの通信が一瞬で終わった場合は、プログレスバーの表示・非表示が一瞬で行われ、ユーザーとしては何かがチラついたように感じることがあるかと思います。

これをいい感じに制御してくれるのが ProgressTimeLatch というわけです。

使い方

かなりシンプルなクラスなので、ソースコードを読めばなんとなくわかるかと思いますが、軽く解説。
( ソースコードはこちら→ https://github.com/chrisbanes/tivi/commit/96e7cae7560ffd358b8c58c47267ed1024df53f6

class ProgressTimeLatch(
        private val delayMs: Long = 750,
        private val minShowTime: Long = 500,
        private val viewRefreshingToggle: ((Boolean) -> Unit)
)

コンストラクタは上記のような感じになっています。

delayMs
Viewを表示するまで遅延させる時間をセットします。

minShowTime
Viewの最低限の表示時間をセットします。

viewRefreshingToggle
Viewの表示・非表示のLambdaをセットします。

既存のコードに適用する場合は、こちらのdiffが参考になりそうです。対象のViewをラップするようにして、今まで表示・非表示を切り替えていたところで、 refreshing を切り替える形。

いい感じに制御してくれる例

下記のような場合を想定します。

ProgressTimeLatch(delayMs = 500, minShowTime = 500) {
 // ProgressBarの表示・非表示
}

・非同期処理が早く(100ms)終わった場合
 → delayMs より小さいのでProgressBarは表示されない(チラつかない)

・非同期処理がやや早く(600ms)終わった場合
 → delayMs より大きいのでProgressBarは表示される
 → minShowTime が残っているので、残り時間分表示して非表示になる(チラつかない)

・非同期処理が遅く(2000ms)終わった場合
 → delayMs より大きいのでProgressBarは表示される
 → delayMsminShowTime の合計以上なので、元の処理が終わったタイミングで非表示になる(チラつかない)

という感じです。便利!

まとめ

  • ProgressTimeLatch はチラつきをいい感じに制御してくれるやつだった
  • 使い方もシンプルなので、使っていきたい
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む