42

getBytes()String オブジェクトのメソッドを呼び出して UnsupportedEncodingException を取得するテスト シナリオをシミュレートする必要があります。

私は次のコードを使用してそれを達成しようとしました:

String nonEncodedString = mock(String.class);
when(nonEncodedString.getBytes(anyString())).thenThrow(new UnsupportedEncodingException("Parsing error."));

問題は、テスト ケースを実行すると、java.lang.String クラスをモックできないことを示す MockitoException が発生することです。

mockito を使用して String オブジェクトをモックする方法、または getBytes メソッドを呼び出したときに String オブジェクトに UnsupportedEncodingException をスローさせる方法はありますか?


問題を説明する詳細は次のとおりです。

これは私がテストしたいクラスです:

public final class A {
    public static String f(String str){
        try {
            return new String(str.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            // This is the catch block that I want to exercise.
            ...
        }
    }
}

これは私のテストクラスです (私は JUnit 4 と mockito を使用しています):

public class TestA {

    @Test(expected=UnsupportedEncodingException.class)
    public void test(){
        String aString = mock(String.class);
        when(nonEncodedString.getBytes(anyString())).thenThrow(new UnsupportedEncodingException("Parsing error."));
        A.f(aString);
    }
}
4

15 に答える 15

47

問題は、StringJavaのクラスがfinalとしてマークされているため、従来のモックフレームワークを使用してモックを作成できないことです。Mockito FAQによると、これはそのフレームワークの制限でもあります。

于 2009-07-03T13:01:02.370 に答える
13

String悪いエンコーディング名で を作成するのはどうですか? 見る

public String(byte bytes[], int offset, int length, String charsetName)

あざけるStringことはほぼ間違いなく悪い考えです。

于 2009-09-05T20:31:16.603 に答える
13

catch ブロックで実行するのが実行時例外をスローすることだけである場合は、Charset オブジェクトを使用して文字セット名を指定するだけで、入力の手間を省くことができます。

public final class A{
    public static String f(String str){
        return new String(str.getBytes(Charset.forName("UTF-8")));
    }
}

このようにして、コンパイラが指示したからといって決して発生しない例外をキャッチすることはありません。

于 2010-05-21T22:43:40.187 に答える
7

他の人が指摘したように、Mockito を使用して最終クラスをモックすることはできません。ただし、より重要な点は、このテストはString.getBytes()例外をスローできることを示すだけであり、明らかに実行できるため、特に有用ではないということです。f()この機能をテストすることを強く希望する場合は、エンコーディング用のパラメーターを追加して、テストに不適切な値を送信できると思います。

また、最終的で静的であるA.f()ため、呼び出し元にも同じ問題が発生しています。Af()

この記事は、100% のコード カバレッジについて独断的にならないように同僚を説得するのに役立つかもしれません: 100% のテスト カバレッジで失敗する方法.

于 2009-12-03T02:32:28.813 に答える
6

そのドキュメントから、JDaveはブートストラップクラスローダーによってロードされたクラスから「最終的な」修飾子を削除できません。これには、すべてのJREクラス(java.lang、java.utilなど)が含まれます。

何でもモックできるツールはJMockitです。

JMockitを使用すると、テストは次のように記述できます。

import java.io.*;
import org.junit.*;
import mockit.*;

public final class ATest
{
   @Test(expected = UnsupportedOperationException.class)
   public void test() throws Exception
   {
      new Expectations()
      {
         @Mocked("getBytes")
         String aString;

         {
            aString.getBytes(anyString);
            result = new UnsupportedEncodingException("Parsing error.");
         }
      };

      A.f("test");
   }
}

完全な「A」クラスは次のとおりです。

import java.io.*;

public final class A
{
   public static String f(String str)
   {
      try {
         return new String(str.getBytes("UTF-8"));
      }
      catch (UnsupportedEncodingException e) {
         throw new UnsupportedOperationException(e);
      }
   }
}

私は実際にこのテストを自分のマシンで実行しました。(元のチェック済み例外をランタイム例外でラップしたことに注意してください。)

@Mocked("getBytes")JMockitがクラス内のすべてをモックするのを防ぐために、部分的なモックスルーを使用しましたjava.lang.String(それが何を引き起こす可能性があるか想像してみてください)。

「UTF-8」は標準の文字セットであり、すべてのJREでサポートする必要があるため、このテストは実際には不要です。したがって、実稼働環境では、catchブロックが実行されることはありません。

ただし、キャッチブロックをカバーする「必要性」または要望は引き続き有効です。では、カバレッジ率を下げずにテストを取り除くにはどうすればよいでしょうか。これが私の考えです。catchassert false;ブロック内に最初のステートメントとしての行を挿入し、カバレッジ測定値を報告するときにコードカバレッジツールでcatchブロック全体を無視するようにします。これは、JMockitCoverageの私の「TODOアイテム」の1つです。8 ^)

于 2009-07-29T22:36:39.663 に答える
3

Mockitoは最終クラスをモックすることはできません。JMockは、JDaveのライブラリと組み合わせることができます。手順は次のとおりです。

JMockは、JVM内のすべてを非ファイナライズするためにJDaveライブラリに依存する以外は、ファイナルクラスに対して特別なことは何もしません。したがって、JDaveのアンファイナライザーを使用して実験し、Mockitoがそれをモックするかどうかを確認できます。

于 2009-07-03T13:01:29.077 に答える
3

また、PowerMock の Mockito 拡張機能を使用して、String などのシステム クラスであっても最終的なクラス/メソッドをモックすることができます。ただし、この場合は getBytes をモックしないことをお勧めします。代わりに、予想されるデータが入力された実際の文字列が使用されるように、予想を設定してください。

于 2009-12-21T09:52:31.817 に答える
1

おそらく、Af(String) は代わりに Af(CharSequence) にする必要があります。CharSequence をモックできます。

于 2010-08-01T01:33:16.900 に答える
1

単体テストのカバー率が特定の値よりも高くなければならないことがプロジェクトの要件です。このような割合のカバレッジを実現するには、UnsupportedEncodingException に関連する catch ブロックをテストでカバーする必要があります。

与えられたカバレッジターゲットは何ですか? 一部の人々は、100% のカバレッジを目指して撮影することは必ずしも良い考えではないと言うでしょう。

その上、catch ブロックが実行されたかどうかをテストする方法はありません。正しい方法は、例外をスローするメソッドを作成し、例外がスローされることを成功基準とすることです。「期待される」値を追加することにより、JUnit の @Test アノテーションでこれを行います。

@Test(expected=IndexOutOfBoundsException.class) public void outOfBounds() {
   new ArrayList<Object>().get(1);
}
于 2009-07-03T15:10:47.517 に答える
1

getBytes(String) に無効な charsetName を渡そうとしましたか?

charsetName を取得するヘルパー メソッドを実装し、テスト内でそのメソッドを無意味な値にオーバーライドできます。

于 2009-07-03T15:12:56.810 に答える
-1

実際には実行できないコード ブロックがあり、100% のテスト カバレッジが必要な場合は、何かを変更する必要があります。

できることは、文字エンコーディングをメンバー変数にし、それを渡すことができるパッケージ プライベート コンストラクターをクラスに追加することです。単体テストでは、文字エンコーディングに意味のない値を指定して、新しいコンストラクターを呼び出すことができます。 .

于 2011-12-17T06:24:37.043 に答える