Как определить, работает ли приложение Android в UI-тестировании с помощью Espresso

Я пишу несколько тестов эспрессо для Android. Я запускаю следующую проблему:

Для правильной работы определенного тестового примера мне нужно отключить некоторые функции в приложении. Поэтому в моем приложении мне нужно определить, выполняю ли я тест Espresso, чтобы отключить его. Тем не менее, я не хочу использовать BuildConfig.DEBUG, потому что я не хочу, чтобы эти функции были отключены в сборке отладки. Кроме того, я хотел бы избежать создания нового buildConfig, чтобы избежать слишком большого количества вариантов сборки, которые нужно создать (у нас уже есть много вариантов).

Я искал способ определить buildConfigField для тестирования, но я не нашел ссылок на Google.

Ответ 1

В сочетании с ответом CommonsWare. Вот мое решение:

Я определил переменную AtomicBoolean и функцию, чтобы проверить, не работает ли она:

private AtomicBoolean isRunningTest;

public synchronized boolean isRunningTest () {
    if (null == isRunningTest) {
        boolean istest;

        try {
            Class.forName ("myApp.package.name.test.class.name");
            istest = true;
        } catch (ClassNotFoundException e) {
            istest = false;
        }

        isRunningTest = new AtomicBoolean (istest);
    }

    return isRunningTest.get ();
}

Это позволяет избежать проверки try-catch каждый раз, когда вам нужно проверить значение, и он запускает проверку только при первом вызове этой функции.

Ответ 2

Объединение Commonsware comment + Comtaler решение здесь, чтобы сделать это для любого тестового класса с использованием среды Espresso.

public static synchronized boolean isRunningTest () {
        if (null == isRunningTest) {
            boolean istest;

            try {
                Class.forName ("android.support.test.espresso.Espresso");
                istest = true;
            } catch (ClassNotFoundException e) {
                istest = false;
            }

            isRunningTest = new AtomicBoolean (istest);
        }

        return isRunningTest.get();
    }

Ответ 3

Основываясь на ответах выше следующего кода Котлина, это эквивалентно:

val isRunningTest : Boolean by lazy {
    try {
        Class.forName("android.support.test.espresso.Espresso")
        true
    } catch (e: ClassNotFoundException) {
        false
    }
}

Затем вы можете проверить значение свойства:

if (isRunningTest) {
  // Espresso only code
}

Ответ 4

Как насчет флага в классе BuildConfig?

android {
    defaultConfig {
        // No automatic import :(
        buildConfigField "java.util.concurrent.atomic.AtomicBoolean", "IS_TESTING", "new java.util.concurrent.atomic.AtomicBoolean(false)"
    }
}

Добавьте это где-нибудь в ваших тестовых классах.

static {
    BuildConfig.IS_TESTING.set(true);
}

Ответ 5

Я предпочитаю не использовать отражение, которое медленно работает на android. У большинства из нас есть кинжал2, настроенный для инъекции зависимости. У меня есть тестовый компонент, настроенный для тестирования. Ниже приведен краткий способ получения режима приложения (тестирование или нормальный):

создать перечисление:

public enum ApplicationMode {
    NORMAL,TESTING;
}

и обычный AppModule:

@Module
public class AppModule {

    @Provides
    public ApplicationMode provideApplicationMode(){
        return ApplicationMode.NORMAL;
    }
}

создайте тестового бегуна, как я:

public class PomeloTestRunner extends AndroidJUnitRunner {

    @Override
    public Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
            return super.newApplication(cl, MyTestApplication.class.getName(), context);
    }
}

Не забудьте объявить его в gradle следующим образом:

defaultConfig {
testInstrumentationRunner "com.mobile.pomelo.base.PomeloTestRunner"
}

Теперь создайте подкласс AppModule с методом переопределения, который будет выглядеть точно так же и не помечать его как модуль над определением класса:

public class TestAppModule extends AppModule{

    public TestAppModule(Application application) {
        super(application);
    }

    @Override
    public ApplicationMode provideApplicationMode(){
        return ApplicationMode.TESTING; //notice we are testing here
    }
}

теперь в вашем классе MyTestApplication, который вы объявили в пользовательском тестовом бегуне, объявлено следующее:

public class PomeloTestApplication extends PomeloApplication {

    @Singleton
    @Component(modules = {AppModule.class})
    public interface TestAppComponent extends AppComponent {
        }

    @Override
    protected AppComponent initDagger(Application application) {
        return DaggerPomeloTestApplication_TestAppComponent.builder()
                .appModule(new TestAppModule(application)) //notice we pass in our Test appModule here that we subclassed which has a ApplicationMode set to testing
                .build();
    }
}

Теперь, чтобы использовать его, просто введите его в производственный код везде, где это возможно:

@Inject
    ApplicationMode appMode;

поэтому, когда ваши тестовые тесты эспрессо будут проверять перечисление, но когда в производственном коде это будет нормальное перечисление.

ps не нужно, но если вам нужно посмотреть, как мой производственный кинжал строит график таким образом и объявляется в подклассе приложения:

 protected AppComponent initDagger(Application application) {
        return DaggerAppComponent.builder()
                .appModule(new AppModule(application))
                .build();
    }

Ответ 6

Я создам два файла, например ниже

src/main/.../Injection.java

ЦСИ/androidTest/.../Injection.java

И в Injection.java я буду использовать другую реализацию, или просто статическую переменную int it.

Поскольку androidTest - это источник, а не часть типа сборки, я думаю, что вы хотите сделать, это сложно.

Ответ 7

Для этого вы можете использовать SharedPreferences.

Установите режим отладки:

boolean isDebug = true;

SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt("DEBUG_MODE", isDebug);
editor.commit();

Проверьте режим отладки:

SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
boolean isDebug = sharedPref.getBoolean("DEBUG_MODE", false);

if(isDebug){
    //Activate debug features
}else{
    //Disable debug features
}

Ответ 8

Если вы используете JitPack с kotlin. Вам нужно изменить имя пакета Espresso.

val isRunningTest : Boolean by lazy {
    try {
        Class.forName("androidx.test.espresso.Espresso")
        true
    } catch (e: ClassNotFoundException) {
        false
    }
}

Для проверки

if (isRunningTest) {
  // Espresso only code
}