Reputation: 311
Need help to write a unit test for the below code using Mockito and JUnit4,
public class MyFragmentPresenterImpl {
public Boolean isValid(String value) {
return !(TextUtils.isEmpty(value));
}
}
I tried below method: MyFragmentPresenter mMyFragmentPresenter
@Before
public void setup(){
mMyFragmentPresenter=new MyFragmentPresenterImpl();
}
@Test
public void testEmptyValue() throws Exception {
String value=null;
assertFalse(mMyFragmentPresenter.isValid(value));
}
but it returns following exception,
java.lang.RuntimeException: Method isEmpty in android.text.TextUtils not mocked. See http://g.co/androidstudio/not-mocked for details. at android.text.TextUtils.isEmpty(TextUtils.java) at ....
Upvotes: 29
Views: 18789
Reputation: 2421
With newer power mock (2.0.9) and mockito (3.9.0) I had. to change execution to this one:
when(TextUtils.isEmpty(any())).thenAnswer((Answer<Boolean>) invocation -> {
CharSequence a = (CharSequence) invocation.getArguments()[0];
return a == null || a.length() == 0;
});
Upvotes: 0
Reputation: 123
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
Upvotes: 3
Reputation: 4745
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;
}
}
Upvotes: 3
Reputation: 705
As a followup to Johnny's answer, to catch TextUtils.isEmpty(null) calls as well, you could use this piece of code.
PowerMockito.mockStatic(TextUtils.class);
PowerMockito.when(TextUtils.isEmpty(any()))
.thenAnswer((Answer<Boolean>) invocation -> {
Object s = invocation.getArguments()[0];
return s == null || s.length() == 0;
});
Upvotes: 2
Reputation: 4849
You should use Robolectric:
testImplementation "org.robolectric:robolectric:3.4.2"
And then
@RunWith(RobolectricTestRunner::class)
class TestClass {
...
}
Upvotes: 4
Reputation: 3060
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;
}
}
Upvotes: 2
Reputation: 235
add this line in your gradle file in case of Android Studio.
android{
....
testOptions {
unitTests.returnDefaultValues = true
}
}
Upvotes: 4
Reputation: 4385
This is a known issue as mentioned by @Exception. In my case, I also stumbled upon same situation but on advice of senior dev decided to use Strings.isNullOrEmpty()
instead of TextUtils.isEmpty()
. It turned out to be a nice way to avoid it.
Update: I should better mention it that this utility function Strings.isNullOrEmpty()
requires Guava library.
Upvotes: 6
Reputation: 1964
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.
Upvotes: 41
Reputation: 1793
Use PowerMockito
Add this above your class name, and include any other CUT class names (classes under test)
@RunWith(PowerMockRunner.class)
@PrepareForTest({TextUtils.class})
public class ContactUtilsTest
{
Add this to your @Before
@Before
public void setup(){
PowerMockito.mockStatic(TextUtils.class);
mMyFragmentPresenter=new MyFragmentPresenterImpl();
}
This will make PowerMockito return default values for methods within TextUtils
You would also have to add the relevant gradle depedencies
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"
Upvotes: 9
Reputation: 2323
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/
Upvotes: 4