我想为Android Activity类编写一个简单的单元测试。在扩展Activity的情况下,该测试运行良好,但是,在扩展AppCompatActivity时,该测试失败并显示:
java.lang.NullPointerException 在android.support.v7.app.AppCompatDelegateImplBase。(AppCompatDelegateImplBase.java:117) 在android.support.v7.app.AppCompatDelegateImplV9。(AppCompatDelegateImplV9.java:149) 在android.support.v7.app.AppCompatDelegateImplV14。(AppCompatDelegateImplV14.java:56) 在android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:202) 在android.support.v7.app.AppCompatDelegate.create(AppCompatDelegate.java:183) 在android.support.v7.app.AppCompatActivity.getDelegate(AppCompatActivity.java:518) 在android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:70) 在activity.MainActivity.onCreate(MainActivity.kt:15) 在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)处 在sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在java.lang.reflect.Method.invoke(Method.java:498) 在activity.MainActivity.onCreate(MainActivity.kt:15)
MainActivity代码:
class MainActivity : AppCompatActivity() {
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
finish()
}
}
使用Mockito测试代码:
private lateinit var mainActivitySpy: MainActivity
@Before
fun setUp() {
mainActivitySpy = spy(MainActivity())
}
@Test
fun `Test case`() {
mainActivitySpy.onCreate(mock())
verify(mainActivitySpy).finish()
}
我尝试添加以下代码,但无济于事。
android {
...
testOptions {
unitTests.returnDefaultValues = true
}
}
是否有任何方法可以仅使用JUnit + Mockito而不使用Roboelectric等其他测试框架来使此代码工作?
答案 0 :(得分:1)
是否有任何方法可以仅使用JUnit + Mockito而不使用Roboelectric等其他测试框架来使此代码工作?
不,没有求助于框架的简便方法。真正的问题是,为什么您甚至想尝试。针对一个模拟了每个依赖关系的Activity的测试开始退化为“测试重言式”,该测试只是在不增加任何值的情况下简单地反映了Activity的逻辑。
Android中的传统观点是,由于很难对Activity,Fragment等进行单元测试,因此它们应尽可能轻巧。您需要的业务逻辑可以由可测试的Presenter或ViewModel处理。您的书或教程应涵盖此内容。
如果必须针对活动编写测试,则可以编写仪表化单元测试,其中在设备上实例化了真实的活动。有关如何操作,请参见official documentation。
答案 1 :(得分:0)
我可以使用PowerMock来工作。
testImplementation 'org.powermock:powermock-api-mockito:1.6.6'
testImplementation 'org.powermock:powermock-module-junit4:1.6.6'
然后在我的测试课中...
@RunWith(PowerMockRunner.class)
@PrepareForTest({ ReportFragment.class })
public class AddEditBeaconActivityTests {
@Test
public void test_onCreate() {
// Mock some data
mockStatic(ReportFragment.class);
MyActivity activity = spy(new MyActivity());
doNothing().when(activity).initScreen();
doNothing().when(activity).setContentView(R.layout.layout);
doReturn(mock(AppCompatDelegate.class)).when(activity).getDelegate();
// Call the method
activity.onCreate(null);
// Verify that it worked
verify(activity, times(1)).setContentView(R.layout.layout);
verify(activity, times(1)).initScreen();
}
}
这就是MyActivity.java的样子...
public class MyActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout);
initScreen();
}
}
之所以起作用,是因为您正在模拟调用super.onCreate()时调用的一些内部方法/类。更具体地说...
doReturn(mock(AppCompatDelegate.class)).when(activity).getDelegate();
传递了模拟的AppCompatDelegate,则可以解决此问题。ReportFragment.injectIfNeededIn(this);
。只需使用mockStatic(ReportFragment.class)模拟此静态类即可模拟此调用。不要忘记将两行添加到课程的顶部:@RunWith(PowerMockRunner.class)
和@PrepareForTest({ ReportFragment.class })
我不会争论您是否应该嘲笑onCreate方法。大卫提出了非常有效的论据。如果您确实需要在单元测试中测试onCreate方法,那么应该可以解决问题。