我正在为Android编写一些Espresso测试。我正在运行以下问题:
为了让某个测试用例正常运行,我需要在应用程序中禁用某些功能。因此,在我的应用程序中,我需要检测我是否正在运行Espresso测试,以便我可以禁用它。但是,我不想使用BuildConfig.DEBUG
,因为我不希望在调试版本中禁用这些功能。另外,我想避免创建一个新的buildConfig来避免创建太多的构建变体(我们已经定义了很多版本)。
我一直在寻找一种方法来定义buildConfigField以供测试,但我无法在Google上找到任何引用。
答案 0 :(得分:30)
结合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检查,并且只在第一次调用此函数时才进行检查。
答案 1 :(得分:24)
结合使用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();
}
答案 2 :(得分:12)
在上述答案的基础上,以下Kotlin代码是等效的:
val isRunningTest : Boolean by lazy {
try {
Class.forName("android.support.test.espresso.Espresso")
true
} catch (e: ClassNotFoundException) {
false
}
}
然后您可以检查属性的值:
if (isRunningTest) {
// Espresso only code
}
答案 3 :(得分:5)
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);
}
答案 4 :(得分:3)
我不想使用在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"
}
现在使用覆盖方法创建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;
因此,当您运行espresso测试时,它将测试枚举,但在生产代码中,它将是正常的枚举。
ps没有必要,但如果你需要看看我的生产匕首如何构建图形,就像这样并在应用程序子类中声明:
protected AppComponent initDagger(Application application) {
return DaggerAppComponent.builder()
.appModule(new AppModule(application))
.build();
}
答案 5 :(得分:2)
我将创建两个文件,如下所示
src / main /.../ Injection.java
的src / androidTest /.../ Injection.java
在Injection.java中,我将使用不同的实现,或者仅使用静态变量。
由于androidTest是源集,而不是构建类型的一部分,我认为你想做的事情很难。
答案 6 :(得分:1)
您可以使用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
}
答案 7 :(得分:0)
如果您将 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
}
答案 8 :(得分:0)
这里有一种方法可以为 react-native Android 应用调整公认的解决方案。
// MainActivity.java
// ...
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegate(this, getMainComponentName()) {
// ...
@Override
protected Bundle getLaunchOptions() {
Bundle initialProperties = new Bundle();
boolean testingInProgress;
try {
Class.forName ("androidx.test.espresso.Espresso");
testingInProgress = true;
} catch (ClassNotFoundException e) {
testingInProgress = false;
}
initialProperties.putBoolean("testingInProgress", testingInProgress);
return initialProperties;
}
};
}
}
然后,您将能够访问 testingInProgress
作为提供给最顶层组件(通常为 App.js
)的道具。从那里您可以使用 componentDidMount
或等效物来访问它并将其放入您的 Redux 商店(或您正在使用的任何东西),以便您的应用程序的其余部分可以访问它。
我们使用它来触发我们应用中的一些逻辑,以帮助我们使用 fastlane 截取屏幕截图。