>

Android 용 Espresso 테스트를 작성 중입니다. 다음과 같은 문제가 발생했습니다.

특정 테스트 사례를 제대로 실행하려면 앱에서 일부 기능을 비활성화해야합니다. 따라서 내 앱에서 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 의견 결합 + 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

    다음 Kotlin 코드 위의 답변을 작성하는 것은 동일합니다.

    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

    안드로이드에서 느린 리플렉션을 사용하지 않는 것을 선호합니다. 우리 중 대부분은 의존성 주입을 위해 dagger2를 설정했습니다. 테스트를 위해 테스트 구성 요소를 설정했습니다. 다음은 응용 프로그램 모드 (테스트 또는 일반)를 얻는 간단한 방법입니다.

    열거 만들기 :

    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"
    }
    
    

    이제 정확히 다음과 같은 override 메소드를 사용하여 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;
    
    

    따라서 에스프레소 테스트를 실행하면 enum을 테스트하지만 프로덕션 코드에서는 일반 enum이됩니다.

    필요하지는 않지만 내 프로덕션 단검이 어떻게 그래프를 빌드하고 애플리케이션 서브 클래스에서 선언했는지 확인해야하는 경우 :

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

관련 자료

  • 이전 angular - ag-grid 열 너비를 백분율로 지정하는 방법이 있습니까?
  • 다음 javascript - 클릭 후 예기치 않은 중복 Ajax 호출