こんにちは私はあなたが私を助けることができることを本当に望みます、私は何日も私の髪を抜いてきたような気がします。
メソッドAの単体テストを記述しようとしています。メソッドAが静的メソッドBを呼び出しています。静的メソッドBをモックしたいのですが。
私はこれが以前に尋ねられたことを知っていますが、Androidはそれ以来成熟していると感じています。そして、テストしたいメソッドを書き直すことなく、そのような単純なタスクを実行する方法がなければなりません。
次に例を示します。最初にテストしたいメソッドです。
_public String getUserName(Context context, HelperUtils helper) {
if(helper == null){
helper = new HelperUtils();
}
int currentUserId = helper.fetchUsernameFromInternet(context);
if (currentUserId == 1) {
return "Bob";
} else {
return "Unknown";
}
}
_
次に、モックしたい静的メソッド:
_public class HelperUtils {
public static int fetchUsernameFromInternet(Context context) {
int userid = 0;
Log.i("HelperUtils ", "hello");
return userid;
}
}
_
他の言語ではこれはとても簡単ですが、Androidで機能させることはできません。 Mockitoを試しましたが、静的メソッドはサポートされていないようです
_HelperUtils helper = Mockito.mock(HelperUtils.class);
Mockito.when(helper.fetchUsernameFromInternet(getContext())).thenReturn(1);
_
このエラー
org.mockito.exceptions.misusing.MissingMethodInvocationException
Powermockを試しましたが、これがAndroidでサポートされているかどうか完全にはわかりません。私のgradleファイルでandroidCompileを使用してpowermockを実行することができましたが、このエラーが発生しました:
エラー:タスク ':app:dexDebugAndroidTest'の実行に失敗しました。 com.Android.ide.common.process.ProcessException:
言うまでもなく、PowerMockito.mockStatic(HelperUtils.class);
は何も返さないため、getUsernameメソッドに何を渡すかわかりません。
どんな助けでもとてもいただければ幸いです。
静的メソッドはどのオブジェクトにも関連していません-helper.fetchUsernameFromInternet(...)
はHelperUtils.fetchUsernameFromInternet(...)
と同じですが(少し混乱します)、このhelper.fetchUsernameFromInternet
が原因でコンパイラ警告が表示されることもあります。
さらに、Mockito.mock
の代わりに、使用する必要がある静的メソッドをモックします:@RunWith(...)
、@PrepareForTest(...)
そしてPowerMockito.mockStatic(...)
-完全な例はここにあります PowerMockito単一の静的メソッドをモックしてオブジェクトを返す
つまり、静的メソッド(およびコンストラクター)のモックは少し注意が必要です。より良い解決策は:
HelperUtils
を変更できる場合は、そのメソッドを非静的にして、通常のMockito.mock
でHelperUtils
をモックできます。
HelperUtils
を変更できない場合は、元のHelperUtils
に委譲するラッパークラスを作成しますが、static
メソッドがなく、通常のMockito.mock
(これはアイデアは、「所有していないタイプをモックしないでください」と呼ばれることもあります)
私はPowerMockitoを使用してこの方法を行いました。
使ってます AppUtils.class
、複数の静的メソッドと関数が含まれています。
静的関数:
public static boolean isValidEmail(CharSequence target) {
return target != null && EMAIL_PATTERN.matcher(target).matches();
}
テストケース:
@RunWith(PowerMockRunner.class)
@PrepareForTest({AppUtils.class})
public class AppUtilsTest {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
PowerMockito.mockStatic(AppUtils.class);
PowerMockito.when(AppUtils.isValidEmail(anyString())).thenCallRealMethod();
}
@Test
public void testValidEmail() {
assertTrue(AppUtils.isValidEmail("[email protected]"));
}
@Test
public void testInvalidEmail1() {
assertFalse(AppUtils.isValidEmail("[email protected]"));
}
@Test
public void testInvalidEmail2() {
assertFalse(AppUtils.isValidEmail("@email.com"));
}
}
編集1:
次のインポートを追加します。
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
これがお役に立てば幸いです。