如何使用 ContentValues 始终为 null 与 android.content.Intent 中的 Method getAction 进行单元测试未被模拟
How to unit test with ContentValues always null vs Method getAction in android.content.Intent not mocked
最近我一直在使用最新的 android studio 进行单元测试,它是 3 beta 6,我发现即使我初始化 ContentValues
它也是空的.我需要它实际上是一个值/初始化 ContentValues
.
我的gradle文件:
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
applicationId "com.cubedelement.soundplanner"
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "org.mockito.testInstrumentationRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
testOptions {
unitTests.returnDefaultValues = true
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:palette-v7:26.1.0'
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.0', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'com.google.dagger:dagger-android:2.11'
implementation 'com.google.dagger:dagger-android-support:2.11' // if you use the support libraries
annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test:rules:1.0.1'
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.google.code.gson:gson:2.8.0'
testImplementation 'junit:junit:4.12'
testImplementation 'org.powermock:powermock-api-mockito2:1.7.0'
testImplementation 'org.powermock:powermock-module-junit4:1.6.5'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'org.mockito:mockito-core:2.8.47'
androidTestImplementation 'org.mockito:mockito-core:2.8.47'
}
等等,还有更多!
所以我还有一个简单的测试是:
import android.content.ContentValues;
public class Test {
@Test public void ContentValuesShouldNotBeNull(){
ContentValues v = new ContentValues();
assertEquals(v, null) // this is true, but I don't want it to be, help!
}
}
这是android工作室的景色
所以我尝试了一个默认的 gradle 文件,发现 contentvalues 不为空。
这是文件:
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion '26.0.1'
defaultConfig {
applicationId "com.example.kelly_vernon.myapplication"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}
老实说,目前我不太了解 gradle,但我知道我的配置(这是一堆支持匕首和其他值的想法)无论如何都不是很好。
尝试其他方法后,我发现这是罪魁祸首:
testOptions {
unitTests.returnDefaultValues = true
}
我想通了我有这个的原因。我在另一个测试意图的区域进行测试,我需要默认值。
有没有办法限制它排除 ContentValues
或相反不包括 Intent
?
好了,解决了。在撰写本文时,您仍然无法对 android 内容 类 进行单元测试,例如 ContentValues
和 Intent
s.
因此,我介绍了Robolectric
。这并不难,但这里有一些变化。
gradle 文件:
testOptions {
unitTests {
returnDefaultValues = true
includeAndroidResources = true // new line
}
}
测试:
import android.content.ContentValues;
@RunWith(RobolectricTestRunner.class) //new line to start robolectric
public class Test {
@Test public void ContentValuesShouldNotBeNull(){
ContentValues v = new ContentValues();
assertNotNull(v, null);
}
}
您需要模拟构造函数,这可以通过 PowerMock 完成:
PowerMockito.whenNew(ContentValues.class).withNoArguments()
.thenReturn(mockContentValues);`
发生这种情况是因为当您的测试开始时 Android 尚未实例化 - 那时您只是 运行ning 普通 Java,这有助于这些单元测试 运行 很快。
请记住,如果您尝试在实际源代码中调用 ContentValues(),您还必须准备调用构造函数的 class,如 here 所述:
@PrepareForTest({ClassWhereContentValuesIsInitialized.class})
退后一步,使用 Robolectric 是 UI end-to-end 测试的绝佳工具,但它目前不允许像 Mockito/Powermock 那样的复杂模拟。这两个框架用于完全不同的目的,并且都可以串联使用 - 但仅切换到 Robolectric 从技术上讲并不能解决所提出的问题。
诚然,为 Android 设置 Mockito 很痛苦,因为通常必须模拟出如此多的样板 Android 逻辑,有些人可能认为复杂的逻辑不应该完全存在于 client-side Android 代码,或者反对一般的单元测试。不过,它可能是适合您的用例的工具。
最近我一直在使用最新的 android studio 进行单元测试,它是 3 beta 6,我发现即使我初始化 ContentValues
它也是空的.我需要它实际上是一个值/初始化 ContentValues
.
我的gradle文件:
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
applicationId "com.cubedelement.soundplanner"
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "org.mockito.testInstrumentationRunner"
vectorDrawables.useSupportLibrary = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
testOptions {
unitTests.returnDefaultValues = true
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:palette-v7:26.1.0'
androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.0', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation 'com.google.dagger:dagger-android:2.11'
implementation 'com.google.dagger:dagger-android-support:2.11' // if you use the support libraries
annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test:rules:1.0.1'
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.google.code.gson:gson:2.8.0'
testImplementation 'junit:junit:4.12'
testImplementation 'org.powermock:powermock-api-mockito2:1.7.0'
testImplementation 'org.powermock:powermock-module-junit4:1.6.5'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'org.mockito:mockito-core:2.8.47'
androidTestImplementation 'org.mockito:mockito-core:2.8.47'
}
等等,还有更多!
所以我还有一个简单的测试是:
import android.content.ContentValues;
public class Test {
@Test public void ContentValuesShouldNotBeNull(){
ContentValues v = new ContentValues();
assertEquals(v, null) // this is true, but I don't want it to be, help!
}
}
这是android工作室的景色
所以我尝试了一个默认的 gradle 文件,发现 contentvalues 不为空。
这是文件:
apply plugin: 'com.android.application'
android {
compileSdkVersion 26
buildToolsVersion '26.0.1'
defaultConfig {
applicationId "com.example.kelly_vernon.myapplication"
minSdkVersion 19
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}
老实说,目前我不太了解 gradle,但我知道我的配置(这是一堆支持匕首和其他值的想法)无论如何都不是很好。
尝试其他方法后,我发现这是罪魁祸首:
testOptions {
unitTests.returnDefaultValues = true
}
我想通了我有这个的原因。我在另一个测试意图的区域进行测试,我需要默认值。
有没有办法限制它排除 ContentValues
或相反不包括 Intent
?
好了,解决了。在撰写本文时,您仍然无法对 android 内容 类 进行单元测试,例如 ContentValues
和 Intent
s.
因此,我介绍了Robolectric
。这并不难,但这里有一些变化。
gradle 文件:
testOptions {
unitTests {
returnDefaultValues = true
includeAndroidResources = true // new line
}
}
测试:
import android.content.ContentValues;
@RunWith(RobolectricTestRunner.class) //new line to start robolectric
public class Test {
@Test public void ContentValuesShouldNotBeNull(){
ContentValues v = new ContentValues();
assertNotNull(v, null);
}
}
您需要模拟构造函数,这可以通过 PowerMock 完成:
PowerMockito.whenNew(ContentValues.class).withNoArguments()
.thenReturn(mockContentValues);`
发生这种情况是因为当您的测试开始时 Android 尚未实例化 - 那时您只是 运行ning 普通 Java,这有助于这些单元测试 运行 很快。
请记住,如果您尝试在实际源代码中调用 ContentValues(),您还必须准备调用构造函数的 class,如 here 所述:
@PrepareForTest({ClassWhereContentValuesIsInitialized.class})
退后一步,使用 Robolectric 是 UI end-to-end 测试的绝佳工具,但它目前不允许像 Mockito/Powermock 那样的复杂模拟。这两个框架用于完全不同的目的,并且都可以串联使用 - 但仅切换到 Robolectric 从技术上讲并不能解决所提出的问题。
诚然,为 Android 设置 Mockito 很痛苦,因为通常必须模拟出如此多的样板 Android 逻辑,有些人可能认为复杂的逻辑不应该完全存在于 client-side Android 代码,或者反对一般的单元测试。不过,它可能是适合您的用例的工具。