可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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 ....
回答1:
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.
回答2:
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"
回答3:
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.
回答4:
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.
- JUnit itself is a single measure for the java code, so try not to use the Android API methods.
Source: http://www.liangfeizc.com/2016/01/28/unit-test-on-android/
回答5:
add this line in your gradle file in case of Android Studio.
android{
....
testOptions {
unitTests.returnDefaultValues = true
}
}
回答6:
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
回答7:
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;
}
}
回答8:
You should use Robolectric:
testImplementation "org.robolectric:robolectric:3.4.2"
And then
@RunWith(RobolectricTestRunner::class)
class TestClass {
...
}
回答9:
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;
});