Подтвердить что ты не робот

Нужна помощь в написании 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) по адресу....

4b9b3361

Ответ 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;

    }

}