【问题标题】:How to call AppCompatActivity onCreate in unit test using Mockito如何使用 Mockito 在单元测试中调用 AppCompatActivity onCreate
【发布时间】:2018-07-04 08:22:44
【问题描述】:

我想为 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(Native Method) 在 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 等?

【问题讨论】:

    标签: android unit-testing mockito


    【解决方案1】:

    我使用 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() 时调用的一些内部方法/类。更具体地说...

    1. 您看到的 NullPointerException 是因为您的模拟类没有 AppCompatDelegate,因此它尝试创建一个。如果您使用 doReturn(mock(AppCompatDelegate.class)).when(activity).getDelegate(); 传入一个模拟的 AppCompatDelegate,则可以解决此问题。
    2. 最终,SupportActivity 将尝试调用ReportFragment.injectIfNeededIn(this);。简单地用 mockStatic(ReportFragment.class) 模拟这个静态类将模拟这个调用。不要忘记将这两行添加到类的顶部:@RunWith(PowerMockRunner.class)@PrepareForTest({ ReportFragment.class })

    我不会争论你是否应该嘲笑 onCreate 方法。大卫提出了一个非常有效的论点。如果您确实需要在单元测试中测试 onCreate 方法,这应该可以解决问题。

    【讨论】:

      【解决方案2】:

      有没有什么方法可以让这段代码使用唯一的 JUnit+Mockito 而没有其他测试框架,如 Roboelectric 等?

      不,不借助框架就没有简单的方法可以做到这一点。真正的问题是为什么你甚至想尝试。针对模拟每个依赖项的 Activity 的测试开始退化为“测试重言式”,其中测试只是反映 Activity 的逻辑而不添加任何值。

      Android 中的传统观点是尽可能保持Activity、Fragments 等轻量级,因为它们难以进行单元测试。您需要的业务逻辑可以由可测试的 Presenter 或 ViewModel 处理。你的书或教程应该涵盖这一点。

      如果您必须针对某个 Activity 编写测试,您可以编写一个仪器化单元测试,其中在设备上实例化一个真实的 Activity。请参阅official documentation 了解如何执行此操作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多