原則として、特にこの問題があるため、(RESTful Web API などの外部リソースを利用しない限り) クラスをモックすることは避けようとしています。クラス A がクラス B の foo メソッドをモックアウトしても、クラス B が実際にその foo メソッドの名前を fooBar に変更した場合でも、テストはパスします。ただし、クラス A が実行時に B.foo を呼び出そうとすると、クラッシュします。したがって、ローカルで利用できるものをモックすることは避けています。
幸いなことに、Dart の状況は、他の動的言語よりも少し良くなっています。たとえば、別のクラスを実装するクラスを作成できます。したがって、FakeB が B を実装する場合、A をテストするときに使用できる関数を FakeB に追加できます。
当然のことながら、コードの callsTo('isLocked') が、実際には isReallyLocked に名前が変更された isLocked という名前のメソッドを実際に参照していることを、リファクタリング フレームワークが認識するのは少々面倒です。ただし、ミラー API を見ると正しい道を進んでいると思います。たとえば、callsTo(isLocked. name ) と記述できれば素晴らしいと思います。そうすれば、VM はモックに対してより多くのチェックを提供できます。
当然のことながら、本当の目的は、API が一致しない場合にテストを失敗させることです。私は mirrors API をいじってみました。
#import('dart:io');
#import("dart:mirrors");
void a() {
print("a");
}
void main() {
String thisFile = "file://${new Directory.current().path}/${new Options().script}";
print(currentMirrorSystem().libraries[thisFile].functions['a'].simpleName);
}
このコードは引き続き "a" を文字列として使用しますが、"a" が関数として存在しない場合は失敗するという利点があります。ちょっと醜くてハッキーですが、探していた方向に向かっています。
あなたができるもう一つのことは次のようなものです:
when(callsTo('isLocked')).alwaysCall(isLocked)
この場合、モッキング システムは、呼び出し元と isLocked 関数の間の仲介者を演じているだけです。このアプローチには 2 つの欠点があります: a) おそらく isLocked の呼び出しを完全に回避しようとしていたと思われます。ただし、いくつかの利点があります。a) isLocked が呼び出されているという事実を記録できます。b) isLocked の名前が変更されている場合は機能しません。つまり、isLocked の名前を変更した人はこのコードを見て、できれば両方の場所を更新します。
別の「ブルートフォース」アプローチは次のとおりです。
void a() {
print("a");
}
String makeSureItExists(obj, String name) {
return obj != null ? name : "NoSuchMethod";
}
void main() {
print(makeSureItExists(a, "a"));
}
これにより、callsTo(makeSureItExists(login, "login")) のようなものを記述できます。