Нужна помощь в написании unit test с использованием Mockito и JUnit4
Нужна помощь для написания unit test для приведенного ниже кода с использованием Mockito и JUnit4,
public class MyFragmentPresenterImpl {
public Boolean isValid(String value) {
return !(TextUtils.isEmpty(value));
}
}
Я попробовал метод ниже:
MyFragmentPresenter mMyFragmentPresenter
@Before
public void setup(){
mMyFragmentPresenter=new MyFragmentPresenterImpl();
}
@Test
public void testEmptyValue() throws Exception {
String value=null;
assertFalse(mMyFragmentPresenter.isValid(value));
}
но он возвращает следующее исключение,
java.lang.RuntimeException: метод isEmpty в android.text.TextUtils не издевались. Подробнее см. http://g.co/androidstudio/not-mocked. в android.text.TextUtils.isEmpty(TextUtils.java) по адресу....
Ответы
Ответ 1
Из-за того, что класс JUnit TestCase не может использовать API-интерфейсы, связанные с Android, мы должны их переделать.
Используйте PowerMockito
для извлечения статического класса.
Добавьте две строки над классом тестового примера,
@RunWith(PowerMockRunner.class)
@PrepareForTest(TextUtils.class)
public class YourTest
{
}
И установочный код
@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);
}
});
}
Это реализует TextUtils.isEmpty()
с нашей собственной логикой.
Также добавьте зависимости в файлы app.gradle
.
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"
Спасибо Behelit
и Exception
ответ.
Ответ 2
Использовать PowerMockito
Добавьте это выше своего имени класса и включите любые другие имена классов CUT (классы под тестом)
@RunWith(PowerMockRunner.class)
@PrepareForTest({TextUtils.class})
public class ContactUtilsTest
{
Добавьте это к своему @Before
@Before
public void setup(){
PowerMockito.mockStatic(TextUtils.class);
mMyFragmentPresenter=new MyFragmentPresenterImpl();
}
Это заставит PowerMockito вернуть значения по умолчанию для методов в TextUtils
Вам также необходимо будет добавить соответствующие gradle параметры
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
Это известная проблема, упомянутая в @Exception. В моем случае я также наткнулся на такую же ситуацию, но по совету старшего разработчика решил использовать Strings.isNullOrEmpty()
вместо TextUtils.isEmpty()
. Это оказалось хорошим способом избежать этого.
Обновление: я должен упомянуть, что эта функция утилиты Strings.isNullOrEmpty()
требует библиотеки Guava.
Ответ 4
добавьте эту строку в ваш файл gradle в случае Android Studio.
android{
....
testOptions {
unitTests.returnDefaultValues = true
}
}
Ответ 5
Это известная проблема из-за положения в тесте "Основы Android", в котором говорится:
Вы можете использовать класс JUnit TestCase для модульного тестирования в классе который не вызывает Android API.
Поведение по умолчанию является проблематичным при использовании таких классов, как Log
или TextUtils
.
Подводя итог:
-
android.jar
покалечен раньше, поэтому некоторое возвращаемое значение Android API может быть не таким, как ожидалось.
- JUnit - это единственная мера для Java-кода, поэтому постарайтесь не использовать методы API Android.
Источник: http://www.liangfeizc.com/2016/01/28/unit-test-on-android/
Ответ 6
Мне удалось решить эту ошибку, запустив тестовый класс со следующим.
@RunWith (RobolectricGradleTestRunner.class)
публичный класс MySimpleTest {
..... куча тестовых примеров
}
Эта страница wiki объясняет более подробно
https://github.com/yahoo/squidb/wiki/Unit-testing-with-model-objects
Ответ 7
Я заменяю всюду в своем проекте TextUtils.isEmpty(...)
следующим образом:
/**
* 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
Вы должны использовать Robolectric:
testImplementation "org.robolectric:robolectric:3.4.2"
И затем
@RunWith(RobolectricTestRunner::class)
class TestClass {
...
}
Ответ 9
В качестве продолжения ответа Джонни, чтобы перехватить вызовы TextUtils.isEmpty(null), вы можете использовать этот фрагмент кода.
PowerMockito.mockStatic(TextUtils.class);
PowerMockito.when(TextUtils.isEmpty(any()))
.thenAnswer((Answer<Boolean>) invocation -> {
Object s = invocation.getArguments()[0];
return s == null || s.length() == 0;
});
Ответ 10
Решение 1:
Я хотел бы предоставить версию Kotlin и Java.
Котлин версия:
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:
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);
});
}
}
Не забудьте добавить зависимости:
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"
Я помню, что нам все еще нужна другая зависимость, но не ясно.
В любом случае вы можете легко исправить отсутствующую зависимость.
Решение 2:
Или вы можете добавить тот же пакет и имя класса с TextUtils
package android.text;
public class TextUtils {
public static boolean isEmpty( CharSequence str) {
return str == null || str.length() == 0;
}
}