Easy Mockでstaticメソッドのmock化はできるか?

このQ&Aのポイント
  • Easy Mockではprivateメソッドはmock化できないとサイトに記述されていたが、同様にstaticメソッドもmock化できないのか疑問がある。
  • publicメソッドは問題なくmock化できるが、staticメソッドをmockに使用すると「no last call on a mock available」というエラーが発生する。
  • 実際に動かしてみたが、予想通りに動作しない。これが設定やプログラムミスなのか、Easy Mockの仕様なのか判別できない。
回答を見る
  • ベストアンサー

Easy Mockについて

別件の質問の別アプローチにてEasy Mockを使用しようと試してみました。 どうもうまくいかないので質問させてください。 Easy Mockではprivateメソッドはmock化できないとサイトに記述されていたのですが、staticメソッドも同様にmock化できないのでしょうか? publicメソッドは問題なくできたのですが、staticメソッドをmockに使用とすると実行時に「no last call on a mock availavle」というエラーがでます。 IMocksControl c = EasyMock.createControl(); Sample s = c.createMock(Sample.class); EasyMock.expect(s.print()).antReturn("test"); EasyMock.replay(s); ・ ・ ・ print()がpublicメソッドならエラーにならないのですが、staticメソッドだとエラーになります(expectの行でエラー)。 staticなので、下記のようなことも試してみました。 EasyMock.expect(Sample.print()).antReturn("test"); そもそもstaticメソッドだけどEasy Mockで試験できるのか?という疑問から実際に動かしてみたのですが、予想通りに動きません。 ただこれが私の設定やプログラムミスで出来ないのか、Easy Mockの仕様なのか判別つかないので、どなたかご存知の方がいましたら教えてもらえないでしょうか?

  • Java
  • 回答数2
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
  • root139
  • ベストアンサー率60% (488/809)
回答No.1

privateメソッドやstaticメソッドに関してのご質問ですので、 Class Extension を使用しているものと仮定してお答えします。 EasyMock で偽装できるのは、オーバーライドできるものだけのようです。 ですので、フィールドやprivate/static/finalのメソッドなどは偽装できないのかと。 ちなみに、staticメソッドはサブクラスで同じシグネチャーのメソッドを実装できますが隠蔽されるだけです。くわしくは参考URLなどを見て下さい。

参考URL:
http://www.javaroad.jp/java_class8.htm
net_work
質問者

お礼

素早いご回答有難うございます。 すみません、Class Extensionの方になります。 なるほど、staticも偽装できないのですね。 私がいまテストしようとしているクラスは下記のようになりますので、Easy Mockでは無理そうですね。 ServletContext sc = pageContext.getServletContext(); ApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(sc); Sample s = context.getBean(id); s.execute(); カスタムタグなのですが、タグハンドラ内からSpringのDIでオブジェクトを取得して実行します。 pageContextはsetterがあるのでMockを渡せますが、WebApplicationContextUtilsのstaticメソッドを最終的に呼び出してしまいます。 getRequiredWebApplicationContextがstaticメソッドでなければEasy Mockで試験できたのでしょうか。 URLについてもオーバライドと隠蔽についても、今までよく知りませんでしたので参考になりました。

net_work
質問者

補足

>getRequiredWebApplicationContextがstaticメソッドでなければEasy Mockで試験できたのでしょうか。 仮にstaticでなくてもカスタムタグ内でnewしていたら(テストコードからWebApplicationContextUtilsのMockを渡せなければ)、どの道無理という認識で合ってますでしょうか。

その他の回答 (1)

  • root139
  • ベストアンサー率60% (488/809)
回答No.2

> テストコードからWebApplicationContextUtilsのMockを渡せなければ、どの道無理・・・ 渡せなければ、おっしゃる通り、無理かと思います。 ですが、もし getRequiredWebApplicationContext メソッドが static ではなかった場合、下記の様にすれば、EasyMock で偽装は出来ます。 ・テスト対象クラスにインスタンスフィールドとして、WebApplicationContextUtilsオブジェクトを持つ。 ・それをコンストラクタかsetterメソッドで置き換えられるようにする。 実際には WebApplicationContextUtils のラッパークラスを作って、テスト対象クラスではそれを使うようにすれば、テスト可能になると思います。 例) -------------------------------------------------------------- public class WebAppContextService { public ApplicationContext getRequiredWebApplicationContext(ServletContext sc) { return WebApplicationContextUtils.getRequiredWebApplicationContext(sc); } } ------------------------------------------------------------------ また、 staticメソッド等を含めたクラス単位での偽装が可能な DJUnit というものも在りますので、これなどを使えば現状のテスト対象(本番)コードでもテストができるかとは思います。 http://works.dgic.co.jp/djwiki/Viewpage.do?pid=@646A556E6974 ただ、テストがしやすいコードを書くことによって設計が改善されるということもとても重要ですので、極力、リファクタリングなどによってMockオブジェクトの挿入が可能にすることをお勧めします。 http://capsctrl.que.jp/kdmsnr/wiki/bliki/?cmd=view&p=StaticSubstitution&key=static DIの考え方も、具象クラスへの依存をコード中から出来るだけ取り除くことが柱になっています。 http://kakutani.com/trans/fowler/injection.html 自動単体テスト関しては、最近出版された「レガシーコード改善ガイド」が非常に参考になると思います。(原書は5年ほど前ですが) http://www.amazon.co.jp/dp/4798116831/

net_work
質問者

お礼

質問内容だけでなく、色々と教えて頂けてとても助かりました。 アドバイス頂いた事を検討して、どのように進めるか考えたいと思います。 本当に有難うございました。一人で調べていて煮詰まっていたので助かりました。

関連するQ&A

  • プログラムの合体。

    jump7799_4836さん 2018/7/2103:34:44 public class Test2 { public static int メソッド () { System.out.println("メソッド()が呼ばれました"); return 0; } public static int メソッド (int i) { System.out.println("メソッド(int i)が呼ばれました"); return i; } public static int メソッド (int i, int j) { System.out.println("メソッド(int i, int j)が呼ばれました"); return i; } public static int メソッド (short s) { System.out.println("メソッド(short s)が呼ばれました"); return s; } public static int メソッド (double d) { System.out.println("メソッド(double d)が呼ばれました"); return (int) d; } } public メソッド class Test2 { public メソッド static void main(String[] args) { Test2.メソッド (); Test2.メソッド (1); Test2.メソッド (1,2); Test2.メソッド (1.1); Test2.メソッド ((short) 1); Test2.メソッド ((double)1); } } kouzou@GD348ZZD9:/WORK$ javac Test2.java Test2.java:29: エラー: class、interfaceまたはenumがありません public メソッド class Test2 { ^ Test2.java:30: エラー: <identifier>がありません public メソッド static void main(String[] args) { ^ エラー2個 2つのプログラムが合体することってあるのですか? いつもすみません。 解説のほど、宜しくお願い申し上げます。

    • ベストアンサー
    • Java
  • Easy-PotoPrintのエラー

    PIXUS TS8230 付属の印刷ソフト Easy-PotoPrint Editor を使用し、 L判写真用紙でプリントを行おうとすると 印刷ボタンを押下後に "印刷中にエラーが発生しました。"とメッセージが表示されてしまい印刷できません。プリンターテストページは問題なく印刷でき、windows10付属アプリのフォトでは問題なくL判写真の印刷ができます。解決方法がわからず困っています。どなたかご教授お願いいします。 ※OKWAVEより補足:「キヤノン製品」についての質問です。

  • 敬称について教えてください

    class parent{ protected final static int val=10; } class Child extends Parent{ private int val=100; public void method(String s){ System.out.println(++val)} } } class Test{ int val=10; public static void main(String args[]){ Parent c=new Child(); c.method("HELLO"); } } 初歩的な質問ですみません。教えて下さい。 上記プログラミングで、下から3行目のc.method・・・ を記入してもコンパイルエラーがおこらないのはなぜでしょうか? 今回newしているのはChildのオブジェクトです。 が、型はParentです。 Parentにはmethodはないし、 なぜこれが許されるのかがわかりません。 分かりやすくおしえてもらえませんか?

    • ベストアンサー
    • Java
  • String typeの引数をつかって 変数はつくれますか?

    いつもお世話になっております。 以下のように、引数を使って、変数をていぎしたいのですが。。。 public static void main(Stirng[] arg){ String hikisuu = "サンプル"; method(hikusuu); } public static void method(String hikisuu){ int hikisuu = 5; } java でこのようなことは可能でしょうか? (実際やったらエラーが出ました...) ほかの方法で、これと同じようなことを実現でくる方法はありますでしょうか? よろしくおねがいします。

    • ベストアンサー
    • Java
  • クラス、インスタンスメソッドについて

    JAVA初心者です。 現在、先人が作ったプログラムの修正作業を行っておりますが、 以下の点に疑問があります。(因みに、先人はJAVAのスペシャリストではありません。) あるクラスが以下の様になっております。 public class Sample { private static Sample s = new Sample(); private Sample() { } /** クラスメンバに存在するインスタンス取得 * @return Sampleクラスの唯一のインスタンス */ public static Sample getInstance(){ return s; } public static void methodA(){ ... } } でこのmethodAを使用するには、以下の様にします。 Sample.getInstance().methodA() これはこれで納得で、うまく動作しますが、これは 結局の所、クラスメソッドにしたかったという事ではないのかな?と 疑問に感じています。つまり、単純に Sample.methodA と呼び出せばうまくいきます。 ところが、たまたまAPIドキュメントを見ていた所、Calendarクラスにもやはり getInstanceというものが存在し、現在日時を取得するのに Calendar.getInstance().getTime() の様に呼び出すと書いてありました。 Sampleクラス、JAVAのCalendarクラス(これに限った事では無いとは思いますが) のこれらのgetInstanceの効用とはなんなんでしょうか? ・クラスの外でnewでインスタンスを作り出さない所 ・それでいてクラスメソッドではない(?)所 この辺りについてご回答よろしくお願いします。

    • ベストアンサー
    • Java
  • オーバーロードの「あいまい」エラーについて

    お世話になっております。 メソッドのオーバーロードにおいて、以下の様な場合にコンパイルエラーが発生します。 環境:JDK1.6.0_13 + eclipse3.3.2 public class Sample { static void meth(long... longs){ System.out.println("long..."); } static void meth(Integer... Integers) { System.out.println("Integer..."); } public static void main(String[] args){ meth(100); } } エラーメッセージ:メソッド meth(long[]) は型 Sample であいまいです (以下、「あいまいエラー」と表記します) 今回のケースでは、なぜこの様なエラーが出てしまうのか、今一つわからずに困っています。 「あいまいエラー」について少し調べを入れてみましたが、 参照型を引数に取るメソッドが複数ある時にnullを渡した時など、 明瞭にわかりやすいケースの例示は見つかったのですが、 今回の様なケースに当てはめて納得の行く情報ソースは見つけられませんでした。 まとめますと、私の欲しい情報は、 可変長引数リストを引数に取るオーバーロードメソッドが複数ある時に、 「あいまいエラー」が発生する規則です。 以上です。よろしくお願いします。

    • ベストアンサー
    • Java
  • 匿名メソッドの動作が分かりません

    C#2.0のサンプルで以下のようなコードがあるのですが 分からない箇所は、goToメソッドのところなのですが、returnの返り値がなく引数のない匿名メソッドをgoToメソッドの引数にしているのです、匿名メソッドの中でreturnの返り値がないならgoToメソッドの引数にはならないのではないでしょうか?動作が分かりません。 public static void WarpTo(Place distPlace) { goTo(distPlace, delegate() { }, delegate() { }); } public static void GoTo(Place distPlace) { // 他人の目がある移動か? bool hasOtherEyes = currentPlace.HasOtherEyes || distPlace.HasOtherEyes; goTo(distPlace, delegate() // 匿名メソッド { //処理(1) }, delegate() // 匿名メソッド { //処理(2) }  ); } このサンプルは一部抜粋で全文は@ITから、 http://www.atmarkit.co.jp/fdotnet/csharp20/csharp20_01/csharp20_01_02.html

  • プロパティにスタティックメソッドを入れられますか?

    質問です、よろしくお願いします。 以下のようなクラスを書いたのですが class test extends aaa { $base_dir = Zend_Registry::get('base'); // 親クラスなど上位の処理何かしらの値が入っているとします public static function index() { return $this->base_dir; } } $test_index = test::index; print $test_index; =============================================== 上記のような簡単なクラスだとして Parse error: parse error in ディレクトリ ~~~ といったエラーがでます エラー行は、この例ですと $base_dir = Zend_Registry::get('base'); のところです。 Zend_Registryのせいなのか、他のスタティックメソッドでも同じなのかわかりませんが 何故エラーになるのかがわかりません・・・ php.iniの設定なのかとも疑ってみましたがそれらしいところは見付かりませんでした。 プロパティにスタティックメソッドをいれることができないということならスッキリ理解できるのですが、そんな話も聞いたことは無かったので、質問させていただきました。 PHPのバージョンは5.2.8です わかりづらい説明で申し訳ありませんがお願いします

    • ベストアンサー
    • PHP
  • Ruby ファイルのリネームでのエラー

    組み込みライブラリのFileクラスを使用してリネームをしようとしているのですが、パスを直接記述した場合はリネーム処理がおこなわれますが、変数で渡した場合は Invalid argument とエラーが出ます。 変数で渡した場合でも出来るようにするには何か別の処理が必要なのでしょうか。 宜しくお願いします。 ○のパターン File::rename("C:\test\01sample01.txt","C:\test\sample01.txt") ×のパターン sample1 = "C:\test\01sample01.txt" sample2 = "C:\test\sample01.txt" File::rename(sample1,sample2)

    • ベストアンサー
    • Ruby
  • 構造体の各データの表示について以下のようなプログラムを作成しました。

    構造体の各データの表示について以下のようなプログラムを作成しました。 #include <stdio.h> struct tb{ char name[20]; char sex; int age; double height; double weight; }; int main(void) { int i; struct tb test[2]; test[0].name="amada" test[0].sex='f'; test[0].age=20; test[0].height=172.5; test[0].weight=62.5; test[1].name="okada"; test[1].sex='f'; test[1].age=21; test[1].height=180.2; test[1].weight=70.8; for(i=0; i<2; i++){ printf("%s %s %d %f %f \n",test[i].name,test[i].sex,test[i].age,test[i].height,test[i].weight); } return 0; } ファイル名を適当にsample.cとしてgcc sample.c した所、以下のようなコンパイルエラーが出ました。 sample.c: In function ‘main’: sample.c:18: error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’ sample.c:18: error: expected ‘;’ before ‘test’ sample.c:23: error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’ このエラーを元にソースをどのように修正したらよいか教えて頂けますでしょうか? よろしくお願いいたします。