Mock the un-mockable Kotlin classes
tl;dr
- Kotlinクラスはデフォルトfinalだからモックできない
- Mockito2ならできるよ
Kotlinのクラス、関数はデフォルトでfinalだからモックできない。
Kotlinのクラス、関数はデフォルトfinalで継承もオーバーライドもできないのでMockitoでモックすることができません。
なので今までは以下のどれかでモック可能な状態にしていました。
- openで継承可能、オーバーライド可能にする
- All-open pluginでクラス/関数をすべてopenにする
- Interfaceに切り出しておく
- PoweMockを利用する
Mockito2.1.0でfinalでもモックできるようになった
Mockito2.1.0でMockMakerというものが導入されました。ただしMockMakerはまだ実験的段階で、デフォルトではオフになっています。
MockMakerを利用する方法は2つ用意されています。
MockMaker fileを用意する。
src/test/resources/mockito-extensions
ディレクトリに以下の一行を含むorg.mockito.plugins.MockMaker
ファイルを置きます。
mock-maker-inline
たった一行のファイルを置くだけなのでそんなに手間ではないかな?
mockito-inlineを利用する
こちらはgradleでdependenciesを書き換えるだけです。
dependencies { // testCompile "org.mockito:mockito-core:2.x.y" testCompile "org.mockito:mockito-inline:2.x.y" }
どちらを利用するか
私は基本的にMockitoは直接扱っておらず、mockito-core
に依存しているKotlin向けのExtensionライブラリを利用しているのでMockMaker fileを置く方法を利用してます。
DroidKaigi 2017でWelcomeトークと2セッション行ってきた。
Welcomeトーク
なんかいつの間にかWelcomeトークでスピーカー代表として話してました!びっくり! 「当たり前と思ってる情報でも誰かにとっては需要がありますよ!プロポーザル出しましょう!」というお話をしました。 いつのまにかCodeZine, giyho.jpに載ってました。
セッション
Pairsで去年やったおっきな仕事の話と、僕がアプリつくるときによくやる構成の話です。
後者30分に対して詰め込みすぎたーと反省してます。
KotlinはJavaわかればかけるし(と、ヤギさんが言ってました!!!!)、RetrofitやOrmaはリポジトリのREADMEを読めばすすっと使えると思います。
問題はRxJavaとDagger2ですよね。僕も初めてのときは意味がわからなかったんですが何時間かコード書いて覚えました。
とりあえずRxJavaとDagger2の補足資料として以下を置いておきますが、どれかしらを読みながらコードを書いてみてその挙動を確かめるのが一番近道だと思います。
詳解RxJava:Scheduler、非同期処理、subscribe/unsubscribe - Qiita
ユースケースで入門するAndroid RxJava1 - Qiita
逆引きよく使うRxJava1.x オペレータ - Qiita
サンプルアプリはこちら github.com
来年が楽しみだね
皆さんお疲れ様でした。DroidKaigi 2018が楽しみですね。
RxJava2へ段階的に移行しよう
RxJava2リリースされましたね、何ヶ月か前に。
OrmaやRetrofitがRxJava2に対応済みなので、個人的にもPairs的にもいつでも移行できる状態ではあります。
といっても大変ですよね。一体いくつのストリームがあると思ってるんですか!!
あれを全部RxJava2へ書き換えていくのはちょっと面倒ですね。できれば徐々に移行を進めていきたいところです。
RxJava1とRxJava2の相互運用
github.com
そこで便利なのが、RxJavaやIxJavaの開発を行っているakarnokdさんが開発しているRxJava2Interopです。
こんな感じで相互に変換を行うことが可能です。
io.reactivex.Observable o2 = RxJavaInterop.toV2Observabe(observable); rx.Observable o1 = RxJavaInterop.toV1Observable(observable, backpressureStrategy);
レイヤーごとにRxJava2に書き換えていく。
RxJava2Interopを利用すれば相互運用ができることがわかりました。 私の個人アプリやPairsではLayered Architectureを採用していますので、下の層の方(DaoやClient)から徐々にRxJava2に書き換えていけば良さそうです。
Kotlinでエレガントに
個人アプリもPairsもKotlinで開発しています。となると、
RxJavaInterop.toV2Observable(observable)
と書くのはちょっと面倒くさいな..となってきます。そこは拡張関数を利用して流れるように書きたいわけです。
observable.toV2Observable()
github.com というわけで、拡張関数を書いてまとめておきました。本家のメソッド名そのままに拡張関数を書いてるので、使い方に関しては本家をみてください。 面倒くさいのでまだJitPackつかってますがそのうちちゃんとあげます。 あとまだテストも書いてないです、そのうち書きます、またはPR待っています。
Java/Kotlin混合プロジェクトで気をつけていること。
弊社Slackの#eureka-kotlinからの転載シリーズ。 プライベートではすべてKotlinでコードを書いているのであまり気にすることがなかったのですが、pairsはJava/Kotlin混合で成り立っているのでKotlinで書いたコードがJavaからどう見えるのかを気にすることがたまにあります。 すべてを網羅しているわけではありませんが、いくつか書いてみました。
Companion object != Static
Kotlinにはstaticメソッドやstaticフィールドはありませんが、これらと同等の役割を持ったcompanion object
が存在します。
fun KotlinFragment: Fragment() { companion object { fun newInstance(...): KotlinFragment { ... } } }
しかしこれをJavaから利用するには以下のようにする必要があります。
KotlinFragment.Companion.newInstance(...);
これはいまいちですね。Javaからの利用が想定される場合には@JvmStatic
アノテーションを利用します。
fun KotlinFragment: Fragment() { companion object { @JvmStatic fun newInstance(...): KotlinFragment { ... } } }
KotlinFragment.newInstance(...);
Property != Field
Kotlinで定義したPropertyはJavaからはアクセサを通して利用することになります。
class Kotlin { val bar = "bar" }
kotlin.getBar();
これをJavaからFieldとして扱うためには@JvmField
を利用します。
class Kotlin { @JvmField val bar = "bar" }
kotlin.bar;
高階関数
Javaでは関数は第一級オブジェクトではありません。 関数を引数に取るKotlinの関数をJava8未満から利用する場合には、匿名クラスを渡す必要があります。
class Kotlin { fun higherOrder(func: ()->Unit) { ... } }
kotlin.higerOrder(new Function0<Unit>() { @Override public Unit invoke() { return null; } });
関数を返すKotlinの関数であれば、FunctionNが返ってきます。
class Kotlin { fun higherOreder(): ()->Unit { ... } }
Function0<Unit> func = kotlin.higerOrder();
予約語
KotlinでJavaの予約後を使ってしまうと、Javaから呼び出すことができません。
kotlin.final()
JavaでKotlinの予約後を使った場合、Kotlinから呼び出すことはできますが扱いにくいです。
java.`is`()
open
これはJavaからの利用に限った話ではありませんが、Kotlinのクラス、関数はopen
キーワードをつけなければすべてJavaでいうfinal
です。
テストを書く際にmockitoを使ってKotlinクラスをモックしようとしても、継承/オーバーライドすることができません。
mockitoを利用する場合にはモック対象にopen
キーワードをつけて継承/オーバーライド可能にしておきましょう。
Kotlin 1.0.6以降であればAll Open
アノテーションを定義することで一括ですべてをopenにすることも可能です。
KotlinのInterfaceはPropertyも定義できるんだよ
そういえば最近は仕事でもKotlinを書いています。同僚をKotlinで洗脳した甲斐があるというものです。 developers.eure.jp
しかし、全員が全員Javaを書く際と同じようにすらすらKotlinを書くことができるわけではないので、私がKotlinのTipsや文法などをつぶやくSlackのチャンネルがあり、みんなにはそれ読んでもらっています。 せっかくなのでこれからは自分のブログにも転載していこうと思います。 多少雑です。
tl;dr
- KotlinのInterfaceはデフォルト実装を定義できる
- KotlinのInterfaceは(バッキングフィールドを持たないものであれば)プロパティを定義できる
そういえば、(1.1からはできるが)data classは継承をサポートしてないので、デフォルト実装やpropertyをもつinterfaceを実装することで、なにかしら有効活用できそうですね。
KotlinのInterface
デフォルト実装を定義できる。
KotlinのInterfaceはJava8のInterfaceと同様に、デフォルト実装を定義できます。
interface Foo { fun doSomething() = "default" } class FooImpl : Foo { } // ------------------- val foo = FooImpl() foo.doSomething() // return "default"
Propertyを定義できる。
JavaではInterfaceにフィールドを定義することはできませんでした。
しかし、KotlinではBacking fieldを持たないPropertyであれば定義する事ができます。
interface Foo { val one: Int } class FooImpl : Foo { override val one = 2 }
Backing Fieldとは
うまく説明できる気がしないのでKotlinコードと、そこから生成されるByteCodeをJavaにデコンパイルしたものの対比をみて察してください。
Javaコード側でfieldの定義されているA, C, Eをbacking fieldを持ったpropertyといいます。
13日目:プロパティとフィールド - Kotlin Advent Calendar 2012 (全部俺)
case A
class Kotlin { val a = 2 } public final class Java { private final int a = 2; public final int getA() { return this.a; } }
case B
class Kotlin { val b: Int get() = 2 } public final class Java { public final int getB() { return 2; } }
case C
class Kotlin { var c = 2 } public final class Java { private int c = 2; public final int getC() { return this.c; } public final void setC(int <set-?>) { this.c = <set-?>; } }
case D
class Kotlin { var d: Int get() = 2 set(value) { } } public final class Java { public final int getD() { return 2; } public final void setD(int value) { } }
case E
class Kotlin { var e: Int = 2 set(value) { } } public final class Java { private int e = 2; public final int getE() { return this.e; } public final void setE(int value) { } }
AnkoでLayout XMLを殺した
そういえば先月頭にRettyさんでAnkoについてLTしたのでスライド置いておきますね。
speakerdeck.com
あ、ちなみに本稿は特にAnkoの解説は行ってないポエムです。
Ankoとは
Kotlin製DSL。Viewを書くのに利用します。
XMLでView書いた場合の以下のような問題を感じてJetBrainsのエンジニアが開発したのがAnko。
- 型安全じゃないし
- null安全じゃないし
- 似たようなことを毎回かかなきゃいけないし
- XMLをパースする分パフォーマンス悪いし
- コードの再利用できないし
こんな感じでViewを書けます
verticalLayout { val name = editText() button("Say Hello") { onClick { toast("Hello, ${name.text}!") } } }
Javaで書いた場合との差が冒頭に貼ったスライドに書いてあるので、興味ある人は見てください。
なにこれ魔法!?🎩
Kotlinの拡張関数とプロパティを利用してます。 拡張関数を引数にとる関数がどうたらこうたら。これも冒頭のスライドに書いてあるので興味のある人は見てください。
XML全部殺してフルAnkoにした
mints-Android-LayeredArchitecture 暇な時に開発してるアプリのViewをすべてAnkoで書いてみました。 (まだ改善できそうなところは多い)
(追記) HEADではもう、LayoutXMLとDatabindingを利用する形に書き換えてしまった。
ActivityやFragmentとは別のファイルにViewをまとめる
AnkoでViewを書いてる部分
class MainUi : AnkoComponent<MainActivity> { private lateinit var viewPager: ViewPager override fun createView(ui: AnkoContext<MainActivity>): View = with(ui) { verticalLayout { val tabLayout = tabLayout { tabMode = TabLayout.MODE_SCROLLABLE tabGravity = TabLayout.GRAVITY_FILL setSelectedTabIndicatorColor(getColor(ctx, R.color.colorPrimary)) }.lparams(width = matchParent, height = wrapContent) viewPager = viewPager { id = 1 offscreenPageLimit = 2 }.lparams(width = matchParent, height = matchParent) tabLayout.setupWithViewPager(viewPager) } } fun showPages(fm: FragmentManager, pages: List<PageAdapter.Page>) { viewPager.adapter = PageAdapter(fm, pages) } }
利用側
class MainActivity: AppCompatActivity() { private val ui = MainUi() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ui.setContentView(this) } }
XMLを書かなくていいのは結構いいですね。今回は一人での実装だったのでただの予想ですが、コードレビューでXMLを読むのが辛いのですが、Ankoなら多少軽減されるかも。 もっと細かい単位でAnkoComponentを実装していけばコードのreuseができそう。
MacBook Pro 13-inch with TouchBar
仕事用のMacBookPro 13inch TouchBar付きが届いたのでその感想。
tl;dr
- 薄い軽い、持ち運ぶ気になった
- ストロークの浅いキーボードなかなか打ちやすいぞ
- TouchIDが最高なことはみんなしってるだろ?
- TouchBarに最適化されたソフトウェア結構いいかも
- TouchBarカスタマイズして便利なショートカットつくれるぞ!
esc
は常に左上にあるから困らねーぞ!- functionキーは
fn
押せばでてくるぞ! - キーボードだとかモニタだとかじゃらじゃらつけないんでUSB Type-Cだけなのはこまらんぞ!
ボディ
前モデルに比べて軽く、薄くなった。
多少のさだが、結構体感できるほどに違う。これは正義。
今後は通勤時にも持ち運びしてもいいかなと思う。
キーボード
MacBookとおなじようなキーボード。
慣れてみるとこれがなかなかいい。
扱い始めて数十分後にはもとのキーボードのストロークの深さが気に食わなくなった。
TouchID
TouchIDが最高なことなんてiPhone/iPadつかってる人にはわかりきったことだよね。
TouchBar
よい。
BetterTouchToolsで独自のボタンをつくれるので、AndroidStudioでよく使うコマンドを割り当てたりした。
ソフトウェアがTouchBarに対応している場合もなかなかおもしろい。
たとえばSafariであれば、favorites画面でbookmark barに設置しているものがTouchBarに出ていたり
メディアの再生を(safariがフォアグラウンドになくても)TouchBarで操作できたり
これ地味に便利ね。safariでなにかメディアを再生してるときに話しかけられた場合、safariにきりかえて...タブひらいて...ってやらなきゃいけなかったのが面倒だったので(面倒だったのでそもそも止めないことも多かった)
Escapeない
気にならない。
物理ボタンではなくなったが左上には常に表示されている。
Functionキーない
以前よりワンストローク増えてしまうが、fn
を押せばTouchBarにFunctionキーが表示されるので困らない。
コマンド類は前述したようにTouchBarのカスタマイズで最適化できる。
TrackPad
カーソルスピード高く設定して使ってるので広くなっても特に恩恵はない。
誤タッチを気にしてるひともいるみたいだけど、ちゃんとパームリジェクション効くから落ち着けって。
とはいうものの、右下クリックをSecondaryClickに割り当ててると困る。
右下に手のひらが置かれてる状態でクリックするとSecondaryClickとして検出される。
諦めて2FingerClickでSecondaryClickにした。は〜。
USB Type-Cしかない
困らない。
外部キーボード??外部モニタ??キーボードもモニタもMBPにすでについてますよ!!
検証端末の接続もこまらない。Nexus5XはもともとUSB Type-Cです。
iPhoneはケーブルかわないとですね。は〜だるい。
電源
MagSafeはその名の通り安全で最高だった。
ただUSB Type-Cにもいいところはある。
- 右からでも左からでも給電できる
- モバイルバッテリーから給電できる
モバイルバッテリーから給電できるの最高でしょう?
総評
満足