mockitoを使用して文字列を模擬する方法?
-
21-08-2019 - |
質問
私は、StringオブジェクトのgetBytes()
メソッドを呼び出すと、私はに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);
}
}
解決
問題は、伝統的なモックフレームワークを使用している模擬することはできませんので、JavaでString
クラスは、finalとしてマークされています。 Mockitoよくある質問によれば、これは同様に、そのフレームワークの制限です。
他のヒント
どのようにちょうど悪いエンコーディング名でString
の作成については?
public String(byte bytes[], int offset, int length, String charsetName)
String
はほぼ確実に悪い考えですモックます。
あなたのcatchブロックでやろうとしているすべては、あなたは自分のキャラクタ・セット名を指定する文字セットオブジェクトを使用して、自分自身にいくつかの入力を保存することができ、実行時例外がスローされた場合。
public final class A{
public static String f(String str){
return new String(str.getBytes(Charset.forName("UTF-8")));
}
}
この方法であなたはコンパイラがあなたを伝えるという理由だけで起こることは決してありません例外をキャッチされていません。
他の人が示されているとおり、あなたは最終的にクラスをモックするMockitoを使用することはできません。しかし、より重要な点は、それだけでString.getBytes()
が、それは明らかに行うことができます例外を投げることができることを実証しているため、テストは特に有用ではないということです。あなたはこの機能をテストについて強く感じた場合、私はあなたがテストに不正な値をf()
して送信するための符号化パラメータを追加することができると思います。
A.f()
は最終的なものとA
が静的であるため、また、あなたがf()
の呼び出し元に同じ問題を引き起こしている。
この記事では、100%のコードカバレッジについてはあまり独断的であるためにあなたの同僚を説得に役に立つかもしれません:<のhref = "http://jasonrudolph.com/blog/testing-anti-patterns-how-to-fail-with -100-テストカバレッジ/」のrel = "noreferrer"> 100%テストカバレッジするで失敗する方法。
そのマニュアルから、JDaveは、ブートストラップクラスローダによってロードされたクラスから「最終」修飾子を削除することはできません。すなわち、(れるjava.lang、java.utilの、などからの)全てJREクラスを含む。
あなたが何かをモックせないツールは、 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ブロックが実行されることはありません。
catchブロックをカバーするために「必要性」や願望とはいえ、まだ有効です。だから、どのようにカバレッジ率を低下させることなくテストを取り除くには?ここに私の考えです:catchブロック内の最初のステートメントとしてassert false;
の行を挿入し、カバレッジ措置を報告する際にコード・カバレッジ・ツールは、全体のcatchブロックを無視しています。これはJMockitカバレッジのための私の「TODO項目」の一つです。 8 ^)
Mockitoは、最終的なクラスをモックすることはできません。 JMockは、JDave缶からライブラリと組み合わせます。 ここで指示をされます。
JMockあなたはJDaveのunfinalizerを使って実験し、Mockitoは、それを嘲笑するかどうか見ることができるので、JVMのすべてをアンファイナライズするJDaveライブラリに依存している以外の最終クラスのための特別な何もしていません。
また、このような文字列としても、システムクラスで、最終的なクラス/メソッドを模擬するためにPowerMockのMockito拡張子を使用することができます。しかし、私はまた、この場合にはGetBytesメソッドをモックと、むしろ本当の予想データが移入文字列になるように設定あなたの期待に試みるに対するアドバイスが代わりに使用されます。
あなたは実行することはできませんコードをテストします。 UTF-8サポートは、すべてのJava VMであることが要求され、参照<のhref = "http://java.sun.com/javase/6/docs/api/java/nio/charset/Charset.html" のrel =」 noreferrer nofollowを "> http://java.sun.com/javase/6/docs/api/java/nio/charset/Charset.html の
これは、プロジェクトの要件であるユニットテストのカバレッジ率なければならないが、与えられた値よりも高いです。報道のように比率を達成するためにテストがにUnsupportedEncodingExceptionに対するcatchブロックをカバーする必要があります。
カバレッジ目標を与えていることは何ですか?一部の人々は、 100%の範囲の撮影が常にではないことを言うだろう良いアイデアでます。
のほかに、それはcatchブロックが行使されたかどうかをテストする方法ません。正しい方法は、例外がスローされるようにする方法を記述し、例外の観測が成功基準を投げられるようにすることです。あなたが「期待される」値を追加することにより、JUnitのの@Testアノテーションで次の操作を行います。
@Test(expected=IndexOutOfBoundsException.class) public void outOfBounds() {
new ArrayList<Object>().get(1);
}
あなたはGetBytesメソッド(文字列)を無効たcharsetNameを渡して試したことがありますか?
あなたがたcharsetNameを取得するヘルパーメソッドを実装し、ナンセンス値にテスト中にそのメソッドをオーバーライドすることができます。
おそらくA.f(文字列)の代わりにA.f(のCharSequence)でなければなりません。あなたがたCharSequenceを模擬することができます。
、ホジェリオの答えを見てみます。
あなたの目標は、コードカバレッジを取得するが、実際に不足しているUTF-8を使用すると、以下の(そしてあなたがまたはJMockitを使用したくないことはできないことを)行うことができ、実行時にどのように見えるかをシミュレートしないようにしている場合のみとします。
public static String f(String str){
return f(str, "UTF-8");
}
// package private for example
static String f(String str, String charsetName){
try {
return new String(str.getBytes(charsetName));
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Unsupported encoding: " + charsetName, e);
}
}
public class TestA {
@Test(expected=IllegalArgumentException.class)
public void testInvalid(){
A.f(str, "This is not the encoding you are looking for!");
}
@Test
public void testNormal(){
// TODO do the normal tests with the method taking only 1 parameter
}
}
あなたは、インタフェースCharSequence
を取るためにあなたの方法を変更することができます:
public final class A {
public static String f(CharSequence str){
try {
return new String(str.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// This is the catch block that I want to exercise.
...
}
}
}
そのように、あなたはまだ文字列を渡すことができますが、あなたが好きなように模擬することができます。
、その後、何かが変更する必要があるだろう。
あなたはどうする可能性は、メンバ変数をコードするキャラクターを作り、そしてあなたがそれを渡すことができますあなたのクラスにパッケージプライベートコンストラクタを追加することです。あなたのユニットテストでは、あなたはナンセンス値のために、新しいコンストラクタを呼び出すことができます文字エンコーディングます。