Need help to write a unit test for the below code using Mockito and JUnit4,
public class MyFragmentPresenterImpl {
public Boolean isValid(String value
This is a known issue, due to a clause in Testing Fundamental of Android which says:
You can use the JUnit TestCase class to do unit testing on a class that does not call Android APIs.
The default behavior is problematic when using classes like Log
or TextUtils
.
To sum up:
android.jar
is mock before, so some Android API return value may not be as expected.Source: http://www.liangfeizc.com/2016/01/28/unit-test-on-android/
I replaces everywhere in my project TextUtils.isEmpty(...)
with this:
/**
* Util class to be used instead of Android classes for Junit tests.
*/
public class Utils {
/**
* Returns true if the string is null or 0-length.
* @param str the string to be examined
* @return true if str is null or zero length
*/
public static boolean isEmpty(@Nullable CharSequence str) {
return str == null || str.length() == 0;
}
}
I was able to solve this error by running the test class with the following.
@RunWith(RobolectricGradleTestRunner.class)
public class MySimpleTest {
.....a bunch of test cases
}
This wiki page explains in greater detail https://github.com/yahoo/squidb/wiki/Unit-testing-with-model-objects
Because of JUnit TestCase class cannot use Android related APIs, we have to Mock it.
Use PowerMockito
to Mock the static class.
Add two lines above your test case class,
@RunWith(PowerMockRunner.class)
@PrepareForTest(TextUtils.class)
public class YourTest
{
}
And the setup code
@Before
public void setup() {
PowerMockito.mockStatic(TextUtils.class);
PowerMockito.when(TextUtils.isEmpty(any(CharSequence.class))).thenAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
CharSequence a = (CharSequence) invocation.getArguments()[0];
return !(a != null && a.length() > 0);
}
});
}
That implement TextUtils.isEmpty()
with our own logic.
Also, add dependencies in app.gradle
files.
testCompile "org.powermock:powermock-module-junit4:1.6.2"
testCompile "org.powermock:powermock-module-junit4-rule:1.6.2"
testCompile "org.powermock:powermock-api-mockito:1.6.2"
testCompile "org.powermock:powermock-classloading-xstream:1.6.2"
Thanks Behelit
's and Exception
's answer.
add this line in your gradle file in case of Android Studio.
android{
....
testOptions {
unitTests.returnDefaultValues = true
}
}
Solution 1:
I would like to provide a Kotlin and a Java version.
Kotlin version:
import android.text.TextUtils
import org.junit.Before
import org.junit.runner.RunWith
import org.mockito.Matchers.any
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
@RunWith(PowerMockRunner::class)
@PrepareForTest(TextUtils::class)
class UserOwnedDataTest1 {
@Before
fun setup() {
PowerMockito.mockStatic(TextUtils::class.java)
PowerMockito.`when`(TextUtils.isEmpty(any(CharSequence::class.java))).thenAnswer { invocation ->
val a = invocation.arguments[0] as? CharSequence
a?.isEmpty() ?: true
}
}
}
Java version:
import android.text.TextUtils;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.Matchers.any;
@RunWith(PowerMockRunner.class)
@PrepareForTest(TextUtils.class)
public final class UserOwnedDataTest2 {
@Before
public void setup() {
PowerMockito.mockStatic(TextUtils.class);
PowerMockito.when(TextUtils.isEmpty(any(CharSequence.class))).thenAnswer((Answer<Boolean>) invocation -> {
CharSequence a = (CharSequence) invocation.getArguments()[0];
return !(a != null && a.length() > 0);
});
}
}
Do not forget to add the dependencies:
testCompile "org.powermock:powermock-module-junit4:1.6.2"
testCompile "org.powermock:powermock-module-junit4-rule:1.6.2"
testCompile "org.powermock:powermock-api-mockito:1.6.2"
testCompile "org.powermock:powermock-classloading-xstream:1.6.2"
I remember that we still need another dependency, but not clearly.
Anyway you could fix the missing dependency easily.
Solution 2:
Or you could add the same package and class name with TextUtils
package android.text;
public class TextUtils {
public static boolean isEmpty( CharSequence str) {
return str == null || str.length() == 0;
}
}