- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在设计一个系统,其中包含一些不太简单的类,这些类需要 Context 对象才能对其进行初始化。这些类使用也需要上下文初始化的第三方类。此类还利用上下文来加载功能所需的大量字符串资源。
问题在于为这些类编写插桩单元测试。当我尝试使用 InstrumentationRegistry.getContext() 获取用于测试的 Context 对象时,我遇到了一个异常,上下文无法找到与该类关联的字符串资源 (android.content.res.Resources $NotFoundException)。
我的问题是:我如何设计这些测试,以便上下文可以检索我需要的字符串资源,并充当第三方类的合适的上下文对象?我只能做这么多模拟,因为其中一些类处理身份验证 token ,这很难模拟。我不可能是唯一在 Android 域中遇到此问题的人,因此我确信对于这个可能常见的问题有一个通用的解决方案。
编辑:正如建议的那样,我尝试在我的项目中集成 Robolectric(版本 3.3.2),但是当我尝试运行我的单元测试时,我遇到了以下错误:
Error:Error converting bytecode to dex:
Cause: Dex cannot parse version 52 byte code.
This is caused by library dependencies that have been compiled using Java 8 or above.
If you are using the 'java' gradle plugin in a library submodule add
targetCompatibility = '1.7'
sourceCompatibility = '1.7'
to that submodule's build.gradle file.
我已尝试将 targetCompatibility 和 sourceCompatibility 行添加到我的 gradle 文件(在多个位置),但无济于事。
这是我的移动 build.gradle:
apply plugin: 'com.android.application'
apply plugin: 'checkstyle'
apply plugin: 'io.fabric'
project.ext {
supportLibVersion = '25.3.0'
multiDexSupportVersion = '1.0.1'
gsonVersion = '2.8.0'
retrofitVersion = '2.2.0'
daggerVersion = '2.4'
butterKnifeVersion = '8.5.1'
eventBusVersion = '3.0.0'
awsCoreServicesVersion = '2.2.+'
twitterKitVersion = '2.3.2@aar'
facebookVersion = '4.+'
crashlyticsVersion = '2.6.7@aar'
autoValueVersion = '1.2'
autoValueParcelVersion = '0.2.5'
autoValueGsonVersion = '0.4.4'
permissionDispatcher = '2.2.0'
testRunnerVersion = '0.5'
espressoVersion = '2.2.2'
junitVersion = '4.12'
roboelectricVersion = '3.3.2'
}
def gitSha = exec('git rev-parse --short HEAD', "unknown");
def gitCommitCount = 100 + Integer.parseInt(exec('git rev-list --count HEAD', "-1"))
def gitTag = exec('git describe --tags', stringify(gitCommitCount))
def gitTimestamp = exec('git log -n 1 --format=%at', -1)
def appId = "com.example.myapp"
def isCi = "true".equals(System.getenv("CI"))
// Uncomment if you wish to enable Jack & Java8
// apply from: 'jack.gradle'
// Uncomment if you wish to enable Sonar
//apply from: 'sonar.gradle'
android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
defaultConfig {
applicationId appId
minSdkVersion 16
targetSdkVersion 25
multiDexEnabled = true
versionCode gitCommitCount
versionName gitTag
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
buildConfigField 'String', 'GIT_SHA', "\"${gitSha}\""
buildConfigField 'long', 'GIT_TIMESTAMP', "${gitTimestamp}L"
}
buildTypes {
debug {
applicationIdSuffix '.debug'
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
qa.initWith(buildTypes.release)
qa {
applicationIdSuffix '.qa'
debuggable true
}
}
lintOptions {
abortOnError false
}
applicationVariants.all { variant ->
def strictMode = !variant.name.equals("release")
buildConfigField 'boolean', 'STRICT_MODE_ENABLED', "${strictMode}"
}
}
configurations.all {
resolutionStrategy {
force "com.android.support:support-annotations:$supportLibVersion"
force "com.squareup.okhttp3:okhttp:3.4.1"
force "com.squareup:okio:1.9.0"
force "com.google.guava:guava:19.0"
}
}
dependencies {
compile "com.android.support:appcompat-v7:$supportLibVersion"
compile "com.android.support:design:$supportLibVersion"
compile "com.android.support:recyclerview-v7:$supportLibVersion"
compile "com.android.support:cardview-v7:$supportLibVersion"
compile "com.android.support:multidex:$multiDexSupportVersion"
compile "com.squareup.retrofit2:retrofit:$retrofitVersion"
compile "com.squareup.retrofit2:converter-gson:$retrofitVersion"
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
compile "com.google.dagger:dagger:$daggerVersion"
annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion"
provided 'javax.annotation:jsr250-api:1.0'
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.jakewharton.timber:timber:4.3.1'
compile "com.jakewharton:butterknife:$butterKnifeVersion"
annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnifeVersion"
compile "org.greenrobot:eventbus:$eventBusVersion"
annotationProcessor "org.greenrobot:eventbus:$eventBusVersion"
compile 'io.reactivex.rxjava2:rxandroid:2.0.0'
debugCompile 'com.squareup.okhttp3:logging-interceptor:3.4.2'
compile "com.google.auto.value:auto-value:$autoValueVersion"
annotationProcessor "com.google.auto.value:auto-value:$autoValueVersion"
compile "com.ryanharter.auto.value:auto-value-parcel-adapter:$autoValueParcelVersion"
annotationProcessor "com.ryanharter.auto.value:auto-value-parcel:$autoValueParcelVersion"
compile "com.github.hotchemi:permissionsdispatcher:$permissionDispatcher"
annotationProcessor "com.github.hotchemi:permissionsdispatcher-processor:$permissionDispatcher"
compile("com.crashlytics.sdk.android:crashlytics:$crashlyticsVersion") {
transitive = true;
}
compile("com.twitter.sdk.android:twitter:$twitterKitVersion") {
transitive = true
}
compile "com.facebook.android:facebook-android-sdk:$facebookVersion"
compile "com.amazonaws:aws-android-sdk-core:$awsCoreServicesVersion"
annotationProcessor "com.amazonaws:aws-android-sdk-core:$awsCoreServicesVersion"
compile "com.amazonaws:aws-android-sdk-apigateway-core:$awsCoreServicesVersion"
annotationProcessor "com.amazonaws:aws-android-sdk-apigateway-core:$awsCoreServicesVersion"
compile "com.amazonaws:aws-android-sdk-cognito:$awsCoreServicesVersion"
annotationProcessor "com.amazonaws:aws-android-sdk-cognito:$awsCoreServicesVersion"
compile "com.amazonaws:aws-android-sdk-cognitoidentityprovider:$awsCoreServicesVersion"
annotationProcessor "com.amazonaws:aws-android-sdk-cognitoidentityprovider:$awsCoreServicesVersion"
compile "com.amazonaws:aws-android-sdk-lambda:$awsCoreServicesVersion"
annotationProcessor "com.amazonaws:aws-android-sdk-lambda:$awsCoreServicesVersion"
compile "com.amazonaws:aws-android-sdk-sns:$awsCoreServicesVersion"
annotationProcessor "com.amazonaws:aws-android-sdk-sns:$awsCoreServicesVersion"
androidTestCompile "junit:junit:$junitVersion"
androidTestCompile "com.android.support.test:runner:$testRunnerVersion"
androidTestCompile "com.android.support.test:rules:$testRunnerVersion"
androidTestCompile "com.android.support.test.espresso:espresso-intents:$espressoVersion"
androidTestCompile "com.android.support.test.espresso:espresso-core:$espressoVersion"
androidTestCompile "com.squareup.retrofit2:retrofit-mock:$retrofitVersion"
androidTestCompile "org.robolectric:robolectric:$roboelectricVersion"
testCompile "junit:junit:$junitVersion"
testCompile 'com.google.truth:truth:0.30'
testCompile 'org.hamcrest:hamcrest-all:1.3'
testCompile "org.robolectric:robolectric:$roboelectricVersion"
}
task checkCodingStyle(type: Checkstyle) {
description 'Runs Checkstyle inspection against Android sourcesets.'
group = 'Code Quality'
ignoreFailures = false
showViolations = false
source 'src'
include '**/*.java'
exclude '**/gen/**'
exclude '**/R.java'
exclude '**/BuildConfig.java'
reports {
xml.destination "$project.buildDir/reports/checkstyle/report.xml"
}
classpath = files()
configFile = file("${rootProject.rootDir}/config/checkstyle/checkstyle.xml")
}
def stringify(int versionCode) {
def builder = new StringBuilder();
def dot = ""
String.format("%03d", versionCode).toCharArray().each {
builder.append(dot)
builder.append(it)
dot = "."
}
return builder.toString()
}
def exec(String command, Object fallback = null) {
def cmd = command.execute([], project.rootDir)
cmd.waitFor()
if (cmd.exitValue() != 0) {
if (fallback == null) {
throw new RuntimeException("'$command' failed: $cmd.errorStream.text")
} else {
return fallback
}
}
return cmd.text.trim()
}
if (isCi) {
build.finalizedBy(checkCodingStyle)
}
最佳答案
接受的答案不是实际的解决方案。在很多情况下,您想要测试与真实 Android 框架的交互。 Robolectric 与任何其他 stub 一样,可能会隐藏一些实际问题。
您的问题是您使用的 InstrumentationRegistry.getContext()
与您的应用使用的不同。根据文档:
Return the Context of this instrumentation's package.
你应该使用 InstrumentationRegistry.getTargetContext()
来代替:
Return a Context for the target application being instrumented.
因为与第一个相反,它可以访问您的资源。
关于android - Android Instrumented 单元测试中的上下文和资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43125268/
这个问题在这里已经有了答案: What is instrumentation? (5 个回答) 4年前关闭。 正如标题所暗示的那样。很多解释真的很模糊,谁能提供一个更可靠的定义? 该术语在 Andro
我正在使用java.lang.instrument包来获取java对象的内存大小(可以嵌套)。 我使用下面的方法来获取对象大小: import java.lang.instrument.Instrum
Xcode Instruments 中是否有一个 Instrument 可以记录我的代码进行的所有调用(无论是否有 Apple 自己的框架)。 最接近的工具似乎是 Time Profiler。 但是,
当我使用 xCode 运行我的应用程序时,所有负载都运行良好。当我使用 Activity Monitor 或 Allocations 的分析模板加载 Instruments 并按下记录时,它加载并运行
如果我尝试使用 import java.lang.instrument.Instrumentation; 它说这个语句无法解决。可能出什么问题了?我使用的是jdk1.6。 最佳答案 您确定这正是您的导
当我尝试运行 SignUpFragmentTest 类时,出现错误“未注册检测!必须在注册检测下运行”。我认为当我使用@Rule 时会抛出错误。 import android.support.test
是否可以在 JUnit 测试中使用 java.lang.instrument.Instrumentation?我正在使用 mockrunner 来模拟一个 Servlet,并想测量 session 中
我最近搬到了另一台电脑,需要重置我的所有环境。 所以,这个测试以前是有效的。 但是我不记得我以前使用的是哪个版本的 Java/JDK。 好吧,问题是: java.lang.instrument.Ill
我是 Xcode 和 iOS 的新手,今天一直在尝试使用 Instruments 工具。有些事情我正在努力解决: 场景: 我创建了一个简单的应用程序,它使用 UISearchBar 过滤 UITabl
我使用 java.lang.instrument.Instrumentation#redefineClasses() 重新定义现有类。有时,我需要重新定义几个类。 如果我一个一个地重新定义类,我就会知
要检查 iOS 应用程序的内存使用情况,请说代码是否为 int n = 1000000; NSObject *bar = [[NSObject alloc] init]; foo = [[NSMuta
我正在尝试通过 Corda Hello world example (特别是 Java 版本)。 我已经到了 nodes should be deployed但这失败了: > ./gradlew cl
(Xcode 4.5) 当从命令行运行仪器时,它第一次可以工作,但直到我重新启动后它才会再次运行。 仪器的详细输出包括: Instruments : Loading template 'file://
关闭。这个问题需要更多focused .它目前不接受答案。 想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post . 2年前关闭。 Improve this questi
我是 zipkin 和 brave api 的新手,用于分发跟踪。我在本地主机上设置了一个 zipkin 服务器,监听端口 9411。我执行了下面的函数,但在我的 zipkin 服务器中没有显示任何跟
我正在开发一个名为 "Cloudnet-v3" 的开源项目。我在本地计算机上使用符号链接(symbolic link)/data 到 IntelliJProjects-Folder 中的数据点。 我得
我目前正在使用 Android 仪器测试测试我的示例应用程序。默认情况下,项目创建 AndroidTest文件夹给我。我只是在文件夹中添加了更多测试用例。 我以前用expresso触发 UI 按钮,但
好的,这是我的问题,如果重复,我深表歉意。我进行了搜索,但找不到任何我认为相关的内容。 当我从 xcode 运行仪器并开始测试我的应用程序是否存在内存泄漏或分配时,我的 iMac 最终开始运行得很慢。
我在 Xcode 中启动 Time Profiler 时遇到问题,无论是 Mac 应用程序还是 iPhone 应用程序。 我尝试过的步骤是打开时间分析器,单击选择目标下拉框,选择我的 iPhone 或
我想调试我的核心动画代码。但是,仪器配置文件不存在,并且在仪器库中也不可用。 我正在使用 Xcode 4。如何安装/访问它并使其正常工作? 最佳答案 核心动画分析只能从设备上获得。如果您正在分析模拟器
我是一名优秀的程序员,十分优秀!