18 Nov 2017, 08:27

PowerMockを使ってJavaコードをテストしてみた

はじめに

仕事で JavaのTesting Frameworkとして Spockを利用する予定があったので、一生懸命勉強していたが、政治的な理由によって Spockではなく JUnitが採用されてしまった!

というわけで、急遽 JUnitで利用できそうな Mockフレームワークを調査。

PowerMockというのがなかなかいけているので、それを調べた。

今回のテスト対象コードは、以前書いたSpock Frameworkのときのと同じです。

package sample;

public class MockSample {
    private MessageManager mgr;

    public void setMgr(MessageManager mgr) {
        this.mgr = mgr;
    }

    public MockSample() {
        mgr = new MessageManagerImpl();
    }

    public void sendMsg(String msg) {
        mgr.send(msg);
    }

    public int sendMsg2(String msg) {
        return mgr.send2(msg);
    }

    public void sendMsg3(String msg) {
        MessageManager mgr2 = new MessageManagerImpl();
       mgr2.send(msg);
    }

    public static int sendMsg4(String msg) {
        return MessageManagerStatic.send(msg);
    }

    private void sendMsg5(String msg) {
        mgr.send(msg);
    }
}
package sample;

public interface MessageManager {
    void send(String msg);
    int send2(String msg);
}
package sample;

public class MessageManagerImpl implements MessageManager {
    @Override
    public void send(String msg) {
        System.out.println(msg);
    }

    @Override
    public int send2(String msg) {
        System.out.println(msg);
        return 0;
    }
}
package sample;

public class MessageManagerStatic {
    public static int send(String msg) {
        System.out.println(msg);
        return 0;
    }
}

PowerMock Install w/ gradle

Gradleをビルドツールで利用しているので、gradleの方法を書く。

公式wikiには、Mavenのやり方が書いてあるので、そちらを参照。

build.gradleの dependenciesに以下を追加する。

もっと最新バージョンが出ているらしいが不安定だとwikiに書いてあったので、安定バージョンを。

dependencies {
    testCompile 'junit:junit:4.12'
    testCompile 'org.powermock:powermock-module-junit4:1.6.2'
    testCompile 'org.powermock:powermock-api-mockito:1.6.2'
}

テスト!テスト!テスト!

テストする内容は、比較のためSpock Frameworkと同じにしてます。

まずは、お決まりのおまじないアノテーション2つを書く

  • @RunWith(PowerMockRunner.class)
  • @PrepareForTest({MockSample.class, MessageManagerStatic.class})

    • MockSample.class … メソッド内のインスタンスモック用
    • MessageManagerStatic … メソッド内のスタティックメソッドモック用

      呼び出し引数と回数をチェック

  • times で 呼び出し回数をチェック

  • Mockito.veirfy(spy).send(“Hello”) で引数にHelloが来たかチェック

@Test
public void 呼び出し引数をチェック() {
    MessageManager spy = PowerMockito.spy(new MessageManagerImpl());

    sample.setMgr(spy);
    sample.sendMsg("Hello");
    sample.sendMsg("Hello");

    Mockito.verify(spy, times(2)).send("Hello");
}

戻り値を返す

  • when(spy.send2(“Hello”)).thenReturn(1) で 1を返す.
@Test
public void 戻り値を返す() {
    MessageManager spy = PowerMockito.spy(new MessageManagerImpl());
    when(spy.send2("Hello")).thenReturn(1);
    sample.setMgr(spy);

    int ret = sample.sendMsg2("Hello");

    Mockito.verify(spy, times(1)).send2("Hello");
    assertThat(1, is(ret));
}

メソッド内で生成されるインスタンスをモックに置き換える

  • PowerMockit.whenNiewでMessageManagerImplがnew されたときに、作成したmockオブジェクトにすり替える。

この機能は、いろんなフレームワークを試しきたが、PowerMock/Mockitoで初めて見た。

@Test
public void メソッド内で生成されるインスタンスをモックに置き換える() throws Exception {
    // https://github.com/powermock/powermock/wiki/MockConstructor
    MessageManagerImpl mock = PowerMockito.mock(MessageManagerImpl.class);
    PowerMockito.whenNew(MessageManagerImpl.class).withNoArguments().thenReturn(mock);

    sample.sendMsg3("Hello");

    Mockito.verify(mock).send("Hello");
}

staticなメソッドをテストする

オブジェクト内のメソッドからstaticメソッドを呼んでいたって、モックを利用することで、戻り値を書き換えることができる。

@Test
public void staticなメソッドをテストする() {
    // https://github.com/powermock/powermock/wiki/Mockito#mocking-static-method
    PowerMockito.mockStatic(MessageManagerStatic.class);
    Mockito.when(MessageManagerStatic.send("Hello")).thenReturn(1);

    int ret = sample.sendMsg4("Hello");

    assertThat(1, is(ret));
}

例外を発生させる

モックのメソッドが呼ばれたら例外を発生させることもできる。 PowerMockito.doThrow(new Exception).when(mock).send(“Hello”)で実現している。

@Test
public void 例外が発生しないことを確認する() {
    try {
        sample.sendMsg("Hello");
    } catch (Exception e) {
        fail(e.getMessage());
    }
}

@Test(expected = IllegalStateException.class)
public void 例外が発生したこと確認する() throws Exception {
    MessageManagerImpl mock = PowerMockito.mock(MessageManagerImpl.class);
    PowerMockito.doThrow(new IllegalStateException()).when(mock).send("Hello");
    PowerMockito.whenNew(MessageManagerImpl.class).withNoArguments().thenReturn(mock);

    sample.sendMsg3("Hello");
}

おわりに

PowerMock, メソッド内で生成されるインスタンスをモックに置き換える機能がとても強力。

しかし、最大の問題点は、ドキュメントが少ないことだ。いろいろネットで情報を漁ってみたものの、情報量が少ない。

やっぱりSpockを使いたいなあ。

今回のコードはgithubにもあげています。

11 Dec 2014, 15:30

JUnit のテストケースをステートフルで利用する

はじめに

JUnit で, 結合テスト (Integration test), シナリオテストを書きたい.

トランザクションごとに長いテストを書く必要がある.

複数のトランザクションを順に処理していったときに, オブジェクトの状態の変化を検証したい.

JUnit はテストケースが独立

はじめ, トランザクションごとにテストケースを書いていたが, うまく動かない.. オブジェクトの状態が初期化されてしまう.

これは, JUnit の設計思想だった.

つまり, 各テストケースは独立だということ. テストで使用するオブジェクトはテストケース内で生成されて, テストケース内で消滅する.

たとえば

たとえば, このテストは失敗する. number は 0 が入っている.

import static org.junit.Assert.*;

import org.junit.Test;

public class MemoryTest {

    static int number;

    @Test
    public void test () {
        number = 1;
    }

    @Test
    public void test2 () {
        assertEquals (1, number);
    }
}

static を利用する

テスト間で状態を引き継ぐためには, 変数に static 修飾子をつける.

こうすると, 各テストケースの独立を破ることができる.

package test;

import static org.junit.Assert.*;

import org.junit.Test;

public class MemoryTest {

    static int number;
    static Foo foo;
    static Foo bar; 
    static Foo pee;     

    @Test
    public void test () {
        number = 1;
        foo = new Foo (1);
        bar = new Foo (foo);
        pee = new Foo ();       
    }

    @Test
    public void test2 () {
        assertEquals (1, number);
        assertEquals (1, foo.i);
        assertEquals (1, bar.foo.i);        
        assertEquals (2, pee.foo.i);
        foo.plus (3);
    }

    @Test
    public void test3 () {
        assertEquals (4, foo.i);
    }

}

class Foo {
    public int i;
    public Foo foo;

    public Foo (int i) {
        this.i = i;
    }

    public Foo () {
        this.foo = new Foo (2);
    }

    public Foo (Foo foo) {
        this.foo = foo;
    }

    public void plus (int i){
        this.i += i;
    }
}

テストの実行順序を制御する

JUnit のテストが実行される順番はランダム.

これだと, ステートフルなテストには不向きだ.

テストの実行順序を指定するには, 以下の方法がある

  • @FixMethodOrder (MethodSorters.NAME_ASCENDING) をクラスの頭に設定
  • メソッド名を 実行したいものから abc 順に変更.
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.junit.FixMethodOrder;

@FixMethodOrder (MethodSorters.NAME_ASCENDING)
public class MemoryTest {

    static int number;
    static Foo foo;
    static Foo bar; 
    static Foo pee;     

    @Test
    public void test () {
        number = 1;
        foo = new Foo (1);
        bar = new Foo (foo);
        pee = new Foo ();       
    }

    @Test
    public void test2 () {
        assertEquals (1, number);
        assertEquals (1, foo.i);
        assertEquals (1, bar.foo.i);        
        assertEquals (2, pee.foo.i);
        foo.plus (3);
    }

    @Test
    public void test3 () {
        assertEquals (4, foo.i);
    }

}

08 Nov 2014, 06:26

コマンドラインから JUnit を使う方法

最近, Eclipse が嫌いになってしまったので, コマンドラインから JUnit を利用する方法を調べてみた.

Environment

  • ArchLinux
  • JUnit 4.11

事前準備

JUnit をダウンロード.

適当なフォルダに junit.jar を配置したあとに, CLASSPATH を通す.

[sourcecode language=”bash” title=””]
export JUNIT_HOME = /usr/share/java
export CLASSPATH = $JUNIT_HOME/junit.jar:$CLASSPATH
[/sourcecode]

コマンドラインから実行

以下のソースを動かしてみる. ここでは, Lab2Test.java というファイル名.

[sourcecode language=”java” title=””]
import static org.junit.Assert.*;
import org.junit.Test;

public class Lab2Test {
public static int num () {
return 10;
}

@Test
public void test () {
assertEquals (10, num ());
}
}
[/sourcecode]

コンパイルは普通に実施.

[sourcecode language=”bash” title=””]
javac Lab2Test.java
[/sourcecode]

コマンドラインから実行するには, java org.junit.runner.JUnitCore [クラス名] という書き方をして実行する.

[sourcecode language=”bash” title=””]
$ java org.junit.runner.JUnitCore Lab2Test
JUnit version 4.11
.
Time: 0.004

OK (1 test)
[/sourcecode]

クラスが増えてきたら, プログラムにクラス名を書く方法もある. 以下, 参照.

Ant を利用する

すこし大きなコードを扱うときはビルドツールとの連携が役に立つ. ここでは, ant を利用してみる.

build.xml を作成.

JUnit で必要な情報は, ここが詳しい.

[sourcecode language=”xml” title=””]














[/sourcecode]

エラー詳細を表示するためには, の 1 行が必要.

Eclipseで自動生成

<div class="outline-text-3" id="text-unnumbered-5">
  <p>
    もっといい方法を発見したので、追記.
  </p>

  <p>
    Eclipseでbuild.xmlは自動生成ができる.
  </p>

  <p>
    自動生成したいプロジェクトを選択して、
  </p>

  <ul class="org-ul">
    <li>
      Eclipseメニューから「ファイル」>「エクスポート」を選択.
    </li>
    <li>
      [エクスポート]ダイアログから, [一般] > [Antビルド・ファイル]を選択.
    </li>
  </ul>

  <p>
    以下のようなbuild.xmlが生成される. 手動で build.xmlを記述するのがバカらしくなった.
  </p>

  <p>
    [sourcecode language=&#8221;xml&#8221; title=&#8221;&#8221;]<br /> <?xml version="1.0" encoding="UTF-8" standalone="no"?><br /> <!&#8211; WARNING: Eclipse auto-generated file.<br /> Any modifications will be overwritten.<br /> To include a user specific buildfile here, simply create one in the same<br /> directory with the processing instruction <?eclipse.ant.import?><br /> as the first entry and export the buildfile again. &#8211;><project basedir="." default="build" name="tdd_by_example"><br /> <property environment="env"/><br /> <property name="ECLIPSE_HOME" value="../../../../usr/share/eclipse/"/><br /> <property name="junit.output.dir" value="junit"/><br /> <property name="debuglevel" value="source,lines,vars"/><br /> <property name="target" value="1.7"/><br /> <property name="source" value="1.7"/>
  </p>

  <p>
    <path id="Junit4.userclasspath"><br /> <pathelement location="../../../../usr/share/java/junit.jar"/><br /> </path><br /> <path id="tdd_by_example.classpath"><br /> <pathelement location="bin"/><br /> <path refid="Junit4.userclasspath"/><br /> </path><br /> <target name="init"><br /> <mkdir dir="bin"/><br /> <copy includeemptydirs="false" todir="bin"><br /> <fileset dir="src"><br /> <exclude name="**/*.ucls"/><br /> <exclude name="**/*.java"/><br /> </fileset><br /> </copy><br /> <copy includeemptydirs="false" todir="bin"><br /> <fileset dir="test"><br /> <exclude name="**/*.ucls"/><br /> <exclude name="**/*.java"/><br /> </fileset><br /> </copy><br /> </target><br /> <target name="clean"><br /> <delete dir="bin"/><br /> </target><br /> <target depends="clean" name="cleanall"/><br /> <target depends="build-subprojects,build-project" name="build"/><br /> <target name="build-subprojects"/><br /> <target depends="init" name="build-project"><br /> <echo message="${ant.project.name}: ${ant.file}"/><br /> <javac debug="true" debuglevel="${debuglevel}" destdir="bin" includeantruntime="false" source="${source}" target="${target}"><br /> <src path="src"/><br /> <src path="test"/><br /> <classpath refid="tdd_by_example.classpath"/><br /> </javac><br /> </target><br /> <target description="Build all projects which reference this project. Useful to propagate changes." name="build-refprojects"/><br /> <target description="copy Eclipse compiler jars to ant lib directory" name="init-eclipse-compiler"><br /> <copy todir="${ant.library.dir}"><br /> <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/><br /> </copy><br /> <unzip dest="${ant.library.dir}"><br /> <patternset includes="jdtCompilerAdapter.jar"/><br /> <fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/><br /> </unzip><br /> </target><br /> <target description="compile project with Eclipse compiler" name="build-eclipse-compiler"><br /> <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/><br /> <antcall target="build"/><br /> </target><br /> <target name="MoneyTest"><br /> <mkdir dir="${junit.output.dir}"/><br /> <junit fork="yes" printsummary="withOutAndErr"><br /> <formatter type="xml"/><br /> <test name="tdd_by_example.MoneyTest" todir="${junit.output.dir}"/><br /> <classpath refid="tdd_by_example.classpath"/><br /> </junit><br /> </target><br /> <target name="tdd_by_example"><br /> <mkdir dir="${junit.output.dir}"/><br /> <junit fork="yes" printsummary="withOutAndErr"><br /> <formatter type="xml"/><br /> <test name="tdd_by_example.MoneyTest" todir="${junit.output.dir}"/><br /> <classpath refid="tdd_by_example.classpath"/><br /> </junit><br /> </target><br /> <target name="junitreport"><br /> <junitreport todir="${junit.output.dir}"><br /> <fileset dir="${junit.output.dir}"><br /> <include name="TEST-*.xml"/><br /> </fileset><br /> <report format="frames" todir="${junit.output.dir}"/><br /> </junitreport><br /> </target><br /> </project><br /> [/sourcecode]
  </p>
</div>

Emacs で利用する

<div class="outline-text-3" id="text-unnumbered-6">
  <p>
    Emacs で ant を実行するときは, -emacs オプションをつける
  </p>

  <p>
    [sourcecode language=&#8221;bash&#8221; title=&#8221;&#8221;]<br /> $ ant -emacs test<br /> [/sourcecode]
  </p>

  <p>
    エラーした場合, エラー箇所にジャンプできる.
  </p>
</div>

08 Sep 2013, 09:45

JUnitでthrowで投げた例外を検証する方法のメモ

最近記事投稿数が少ないので、ごまかし程度にメモを。

錆びついたJavaの知識にオイル刺しをしている日々ですが、今日は例外処理をJUnitで実施する方法を調べました。

まずは、Javaでの例外の投げ方。以下の用に記述することで、例外を投げてプログラムを終了させることができます。

throw new (エラー)

たとえば、キューにエンキューしたときに、NULLをエンキューしようとしたときは、以下のようにしてjava.lang.NullPointerExceptionの例外を投げる。

public void addFirst(Item item)
  {
    if(item == null)
      throw new java.lang.NullPointerException();
        ...
}

これを、Junitで期待した例外で終了したかどうかを検証するためには、try、catchを利用する。fail()がコールされないことを持ってして、成功と判断する。なかなかトリッキーな方法だ。

 try{
   (例外を発生させる関数);
   fail("Error");
 }catch((エラー) expected){ }

たとえば、以下のようなテストを記述する。

@Test
public void DequeAddFirstNull()
{
 Deque que = new Deque();

 try{
   que.addFirst(null);
   fail("Error");
 }catch(NullPointerException expected){ }
}

17 Jan 2013, 22:49

hamcrestとJUnitの依存関係メモ

hamcrest関係のエラーでハマったので、メモ。

java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch

エラーメッセージ

java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V
     at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:18)
     at org.junit.Assert.assertThat(Assert.java:865)
     at test.endtoend.auctionsniper.FakeAuctionServer$SingleMessageListener.receivesAMessage(FakeAuctionServer.java:71)
     at test.endtoend.auctionsniper.FakeAuctionServer.hasRecievedJoinRequestFromSniper(FakeAuctionServer.java:51)
     at test.endtoend.auctionsniper.AuctionSniperEndToEndTest.sniperJoinnAuctionUntilAuctionCloses(AuctionSniperEndToEndTest.java:14)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     at java.lang.reflect.Method.invoke(Method.java:601)
     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
     at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
     at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

原因

junit.jarには、org.hamcrest.Matcher(aとする)ライブラリが一緒に入っている。
外部のhamcrest(bとする)を入れていると、JUNITはaではなく、bを参照しようとして、エラーする。

解決方法

junit.jar ではなく、 junit-dev-.jarを使う。
junit-dev.jarはhamcrestを含んでいないJUNITライブラリ。
こっちを利用することで、junitとhamcrestの依存関係は解消する。

参考

NoClassDefFoundError: org/hamcrest/MatcherAssert

エラーメッセージ

java.lang.NoClassDefFoundError: org/hamcrest/MatcherAssert
     at org.junit.Assert.assertThat(Assert.java:865)
     at test.endtoend.auctionsniper.FakeAuctionServer$SingleMessageListener.receivesAMessage(FakeAuctionServer.java:71)
     at test.endtoend.auctionsniper.FakeAuctionServer.hasRecievedJoinRequestFromSniper(FakeAuctionServer.java:51)
     at test.endtoend.auctionsniper.AuctionSniperEndToEndTest.sniperJoinnAuctionUntilAuctionCloses(AuctionSniperEndToEndTest.java:14)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     at java.lang.reflect.Method.invoke(Method.java:601)
     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
     at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
     at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: java.lang.ClassNotFoundException: org.hamcrest.MatcherAssert
     at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
     at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
     at java.security.AccessController.doPrivileged(Native Method)
     at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
     at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
     at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
     at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
     … 28 more

問題

hamcrestのバージョンが古いのが原因。

解決

hamcreat を1.1から1.3にしたら解決。

参考

10 Dec 2012, 23:37

EclipseにJMockを入れてSecurityExceptionが発生。

EclipseにJMockを入れたところ、java.lang.SecurityExceptionという例外が発生した。

java.lang.SecurityException: class “org.hamcrest.TypeSafeMatcher”‘s signer information does not match signer information of other classes in the same package at java.lang.ClassLoader.checkCerts(ClassLoader.java:943) at java.lang.ClassLoader.preDefineClass(ClassLoader.java:657) at java.lang.ClassLoader.defineClass(ClassLoader.java:785) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:449) at java.net.URLClassLoader.access$100(URLClassLoader.java:71) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:423) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:356) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:791) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:449) at java.net.URLClassLoader.access$100(URLClassLoader.java:71) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:423) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:356) at org.jmock.internal.InvocationExpectationBuilder.createExpectationFrom(InvocationExpectationBuilder.java:86) at org.jmock.internal.InvocationToExpectationTranslator.invoke(InvocationToExpectationTranslator.java:19) at org.jmock.internal.FakeObjectMethods.invoke(FakeObjectMethods.java:38) at org.jmock.lib.JavaReflectionImposteriser$1.invoke(JavaReflectionImposteriser.java:33) at $Proxy8.someExternal(Unknown Source) at mock_sampleTest$1.(mock_sampleTest.java:45) at mock_sampleTest.testSome(mock_sampleTest.java:44) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66) at org.jmock.integration.junit4.JMock$1.invoke(JMock.java:37) at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:105) at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86) at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94) at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84) at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49) at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:98) at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:61) at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:54) at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:52) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

環境

  • Eclipse 4.2
  • JUnit 4
  • JMock2

原因

EclipseのJUnitプラグインに含まれるHamcrestと、jMockのHamcrestのバージョンが異なっているみたい。

EclipseをダウンロードしてきたときのデフォルトJUnitにJMockを追加したら発生した。

解決方法

このページを参考 :

http://stackoverflow.com/questions/4755442/jmock-dependency-issue

以下の解決方法が提示されている。

  • junit.jarの代わりに、junit-dep.jarを使う
  • Eclipseのビルド・パスで、hamcrest.jarをJUnitライブラリの前ではなく、あとに並び替える。

The solution is simple – make sure that hamcrest.jar is before the JUnit library included by Eclipse in the classpath.

I believe if you look at the “Order and Export” tab in the java build path property (Configure Build Path), you will find that the JUnit jar is above the hamcrest.jar. You can move hamcrest above the JUnit jar here and the problem will go away.

  • 重複しているJUnitのHamcrestを削除。

自分は、Eclipseデフォルトのプラグインを削除して、外部から落としてきたJUnitをビルド・パスに設定し直すことで、解決した。ビルド・パスの設定は、以下のエントリを参照。

JUnitのインストールとEclipseでの使い方まとめ

image

04 Dec 2012, 14:33

JUnitのインストールとEclipseでの使い方まとめ

JUnitをEclipseで利用する方法をメモします。

環境

  • Windows 7 64bit
  • Eclipse 4.2 Juno
  • Java SE 7.9

JUnitはJava用の単体テストフレームワーク

JUnitとは、Java用の単体テストフレームワーク。

Javaでのロジックテストが簡単にできる、お助けツール。

(Wikipedia: http://ja.wikipedia.org/wiki/JUnit)

この本がJUnitでは、一番有名。TDDのバイブル。

 

JUnitのダウンロードとインストール

JUnitを手に入れる

JUnitはGuitHubより落としてこれる。

JUnitのインストールは、落としてきたフォルダを任意の場所に置くだけ。

(ここではC:\src\junitにおいた)

フォルダに環境変数のパスを通す。

[コントロールバネル] > [システム] > [システムの詳細設定] > [環境変数]を選択。
下段のシステムの環境変数の中からPathを選択して、[編集]を選択。
すでに入っている値の最後に”;”をつけてから、パスを追加する。

C:\src\junit

EclipseでのJUnit ビルド・パスの設定

EclipseでJUnitを利用するために、ビルド・パスを通す。

プロジェクトを選択して、[ブロパティ] > [Javaのビルドパス]を選択。

[ライブラリ]タブ > [ライブラリの追加] > [ユーザライブラリ] > [次へ]

[ユーザライブラリ] > [新規]を選択。

ライブラリを作成するために、[JUnit4]と名前をつける。

続いて、[外部Jar追加]。

ここで、先ほどおいたファイルの中にあるjunit-4.11.jarを選択する。

Eclipse JUnit プラグインを利用する

Eclipseでは, Eclipse JUnit プラグインを利用すると簡単にテストケースが作成できる。

(Eclipse JDTには標準で入っている)

テストコードを書きたいソースコードを右クリックして、[新規] > [JUnitテストケース]を選択。今回のテスト対象は、以下の通り。メソッドより期待値が返されるかをテストする。

public class sample {
    public static int num() {
        return 10;
    }
}

ここでは、新規JUnit 4テストケースを選択。とりあえず、細かい設定は置いておいて、完了を選択。テストケースが自動生成される。

import static org.junit.Assert.*;

import org.junit.Test;

public class sampleTest {

    @Test
    public void test() {
        fail("まだ実装されていません");
    }

}

JUnitテストの実行

テストの失敗

プロジェクトを選択して、右クリック。

[実行 > [JUnitテストの実行] を選択して、テストケースを実行する。

まだなにも期待値を書いていないので、テストは失敗する。

image

テストの成功

fail(“まだ実装されていません”);の部分を置き換えてテスト実行すると、テストは成功する。

assertEquals(10, sample.num());

image

assertEqualsは、期待値(10)と結果(sample.num() )を比較する関数。

等しければテストは成功する。

assertEqualsだけ覚えれば、とりあえずどんなテストでも書ける(乱暴な言い方)。