如何检测android应用程序是否正在使用Espresso运行UI测试
我正在为Android编写一些浓缩咖啡测试。我正在运行以下问题: 为了让某个测试用例正常运行,我需要禁用应用程序中的一些功能。因此,在我的应用程序中,我需要检测我是否正在运行浓缩咖啡测试,以便禁用它。但是,我不想将如何检测android应用程序是否正在使用Espresso运行UI测试,android,android-espresso,ui-testing,Android,Android Espresso,Ui Testing,我正在为Android编写一些浓缩咖啡测试。我正在运行以下问题: 为了让某个测试用例正常运行,我需要禁用应用程序中的一些功能。因此,在我的应用程序中,我需要检测我是否正在运行浓缩咖啡测试,以便禁用它。但是,我不想将BuildConfig.DEBUG用于,因为我不希望在调试生成中禁用这些功能。此外,我希望避免创建新的buildConfig,以避免创建太多的构建变体(我们已经定义了很多风格) 我正在寻找一种为测试定义buildConfigField的方法,但在Google上找不到任何参考。您可以使用
BuildConfig.DEBUG
用于,因为我不希望在调试生成中禁用这些功能。此外,我希望避免创建新的buildConfig,以避免创建太多的构建变体(我们已经定义了很多风格)
我正在寻找一种为测试定义buildConfigField的方法,但在Google上找不到任何参考。您可以使用SharedReferences进行此操作 设置调试模式:
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
}
检查调试模式是否:
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
}
结合Commonware的评论。以下是我的解决方案: 我定义了一个
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检查,并且它只在您第一次调用此函数时运行检查。结合Commonware comment+Comtaler的解决方案,这里有一种方法可以为使用Espresso框架的任何测试类执行此操作
private static AtomicBoolean isRunningTest;
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();
}
基于上述答案,以下Kotlin规范等效:
val isRunningTest : Boolean by lazy {
try {
Class.forName("android.support.test.espresso.Espresso")
true
} catch (e: ClassNotFoundException) {
false
}
}
然后可以检查属性的值:
if (isRunningTest) {
// Espresso only code
}
我不喜欢使用反射,这在android上很慢。我们大多数人都为依赖注入设置了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"
}
@Inject
ApplicationMode appMode;
现在,创建AppModule with override方法的子类,该方法与下面的方法完全相同,并且不要将其标记为类定义上方的模块:
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();
}
}
现在使用它只需将其注入生产代码中,如下所示:
defaultConfig {
testInstrumentationRunner "com.mobile.pomelo.base.PomeloTestRunner"
}
@Inject
ApplicationMode appMode;
因此,当您运行浓缩咖啡测试时,它将测试enum,但在生产代码中,它将是普通enum
ps不需要,但如果您需要了解my production dagger是如何构建图形的,它如下所示,并在应用程序子类中声明:
protected AppComponent initDagger(Application application) {
return DaggerAppComponent.builder()
.appModule(new AppModule(application))
.build();
}
我将创建两个文件,如下所示 src/main/../Injection.java src/androidTest/../Injection.java 在Injection.java中,我将使用不同的实现,或者只使用一个静态变量
由于androidTest是源代码集,而不是构建类型的一部分,我认为您想要做的很难。在
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);
}
如果您正在对kotlin使用JitPack。您需要更改浓缩咖啡的包装名称
val isRunningTest : Boolean by lazy {
try {
Class.forName("androidx.test.espresso.Espresso")
true
} catch (e: ClassNotFoundException) {
false
}
}
检查
if (isRunningTest) {
// Espresso only code
}
下面是一种为react原生Android应用程序调整公认解决方案的方法
//MainActivity.java
// ...
@凌驾
受保护的ReactActivityDelegate createReactActivityDelegate(){
返回新的ReactActivityDelegate(此,getMainComponentName()){
// ...
@凌驾
受保护的捆绑包getLaunchOptions(){
Bundle initialProperties=新Bundle();
布尔检验过程;
试一试{
Class.forName(“androidx.test.espresso.espresso”);
TestingProgress=真;
}catch(classnotfounde异常){
testingprogress=false;
}
putBoolean(“testingprogress”,testingprogress);
返回初始属性;
}
};
}
}
然后,您将能够访问testingprogress
,作为最顶级组件的道具(通常是App.js
)。从那里,您可以使用componentDidMount
或等效工具访问它,并将其放入Redux应用商店(或您正在使用的任何东西),以便让应用程序的其余部分可以访问它
我们使用它来触发应用程序中的一些逻辑,以帮助我们使用fastlane截图。一个黑客解决方案是
Class.forName()
,以查看您的测试代码是否在VM中:您解决了这个问题吗?是的。我将发布我的解决方案,使用布尔(非布尔)对象而不是AtomicBoolean类怎么样?使用AtomicBoolean
不是线程保存。您需要使用单个finalAtomicBoolean
的setters,而不是检查null
并创建一个新的。目前,这与使用普通的布尔值
保存一样。但是如果该方法是同步的,那么volatile boolean(volatile for visibility)就足够了,并且是完全线程安全的,对吗?没有回答这个问题。androidx.test.espresso.espresso for jet Back我怀疑在测试这两个文件是否放在同一个包中时会导致生成错误…这帮助我避免了在测试格式化时为一行需要不同的代码编写大量代码:选择代码并单击{}
编辑器中的图标还有一件事,迁移到androidX后应该是->Class.forName(“androidX.test.espresso.espresso”)