kobakei's blog

プログラミングの話や技術系イベントの話をゆるく書くブログです

AndroidプロジェクトでSpek 2.0 RC1を動かす

色々なものに複雑に依存しているので整理してみました。

依存関係

Spek本体

  • Spek
    • まずは当然これ

Spek2が必要とするもの

android junit5が必要とするもの

  • JUnit5
  • Android Gradle Plugin 3.2.0以上
  • Gradle 4.7
    • 最新のAndroid Studioでプロジェクトを作成するとデフォルトではGradle 4.6を使っているので注意

手順

1. Gradleのバージョンアップ

gradle/wrapper/gradle-wrapper.properties を開き、distributionUrlのバージョン番号を更新。本記事執筆時の最新は4.10.2なので4.10.2と書き換える。

distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

Gradle Syncしてダウンロードする。一応この状態でビルドが通るか確認する。

2. android-junit5 & JUnit5の追加

android-junit5のREADMEに従ってbuild.gradleを編集していく。

buildscript {
  dependencies {
    classpath "de.mannodermaus.gradle.plugins:android-junit5:1.3.1.1"
  }
}
  • モジュールのbuild.gradleの一番上にapply plugin、dependenciesにJUnit5を追加する(JUnit4の依存は消す)
apply plugin: "de.mannodermaus.android-junit5"

dependencies {
  testImplementation "org.junit.jupiter:junit-jupiter-api:5.3.1"
  testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.3.1"
}

JUnit4で書かれたテストがあったらテストは失敗するかもしれないが、ビルドが通るか再度確認しておく。

3. Spekの追加

Android用のセットアップガイドがあるので、これに従って再びモジュールのbuild.gradleを編集していく。

  • テストエンジンの指定
android {
    ...
    testOptions {
        junitPlatform {
            filters {
                engines {
                    include 'spek2'
                }
            }
        }
    }
}
  • 依存関係の追加
dependencies {
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

    // spek
    testImplementation "org.spekframework.spek2:spek-dsl-jvm:$spek_version"
    testImplementation "org.spekframework.spek2:spek-runner-junit5:$spek_version"

    // spek requires kotlin-reflect, omit when already in classpath
    testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}

これで終わり。Gradle Syncしておく。

4 テストを書く

あとはテストを書いていくだけ。

import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe

object MyAndroidSpekTest : Spek({
    describe("a") {
        context("b") {
            it("c") {
                ...
            }
        }
    }
})

おまけ: Androidフレームワークに依存しないモジュールの場合

SpekのJVM用ガイドに従うだけでよい。android-junit5の手順は不要。

apply plugin: 'kotlin'

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    //implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"

    // junit5
    testImplementation "org.junit.jupiter:junit-jupiter-api:5.3.1"
    testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.3.1"

    // spek2
    testImplementation('org.spekframework.spek2:spek-dsl-jvm:2.0.0-rc.1') {
        exclude group: 'org.jetbrains.kotlin'
    }
    testRuntimeOnly('org.spekframework.spek2:spek-runner-junit5:2.0.0-rc.1') {
        exclude group: 'org.junit.platform'
        exclude group: 'org.jetbrains.kotlin'
    }
    testRuntimeOnly "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}


test {
    useJUnitPlatform {
        includeEngines 'spek2'
    }
}

エンジニアリングマネージャーという仕事について

今自分が働いている会社ではエンジニアリングマネージャーという肩書で仕事をしています。「ああ、エンジニアのマネジメントをする人ね」ってことなんですが、具体的にどういうことを考えてどういう仕事をやってるかを実際にやってみて分かったこともあるのでまとめておこうと思います。

一応注意としては、「自分はこう考えて仕事してるよ」っていうだけの話で、会社や組織によっては全然違うことを考えたり実行してる人も一杯いると思います。自分の仕事はピープルマネジメントがメインです。

続きを読む

#iOSDC に採択されました

表題の通りです。

去年の年末に社内のiOSリソース不足が理由で、AndroidエンジニアからiOSエンジニアに転向しましたiOSやるからにはでかいカンファレンスで喋れるくらいのレベルになるぞ」という目標を密かに掲げてたんですが、これで一応達成見込みが立ちました。

続きを読む

Kingfisherのリクエストヘッダーを書き換える

KingfisherのCheat Sheetより。AnyModifierを使う。

let modifier = AnyModifier { request in
    var r = request
    r.setValue("", forHTTPHeaderField: "Access-Token")
    return r
}       
imageView.kf.setImage(with: url, placeholder: nil, options: [.requestModifier(modifier)])

毎回オプションにAnyModifierを渡すのがめんどくさい場合は、KingfisherManager経由でセットすればよい。

KingfisherManager.shared.defaultOptions.append(.requestModifier(modifier))

BottomSheetDialogFragmentの使い方

あまりまとまってないようなのでメモ。

昔は setupDialog をオーバーライドしていたが、サポートライブラリが @RestrictTo(LIBRARY_GROUP) を付けるようになったので警告が出る。代わりに、 onCreateDialog をオーバーライドして中でビューを作成するのがよさそう。

class MyBottomSheet : BottomSheetDialogFragment() {

    companion object {
        // Fragmentと同様、インスタンス生成はstaticメソッドで行う
        fun newInstance(): MyBottomSheet = MyBottomSheet()
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = super.onCreateDialog(savedInstanceState)

        // dialogに、自分で作ったビューをセットする
        val inflater = LayoutInflater.from(context)
        val binding: MyBottomSheetBinding = MyBottomSheetBinding.inflate(inflater)
        dialog.setContentView(binding.root)

        return dialog
    }
}