【问题标题】:How to mock Kotlin's kotlinx.android.synthetic views in Android如何在 Android 中模拟 Kotlin 的 kotlinx.android.synthetic 视图
【发布时间】:2018-04-07 22:24:56
【问题描述】:

我有一个用 Kotlin 编写的片段。我使用

导入布局视图
import kotlinx.android.synthetic.main.my_fragment_layout.

在我的一种方法中,我正在设置 TextView 的文本:

fun setViews() {
    myTextView.text = "Hello"
    // In Java I would have used:
    // (getView().findViewById(R.id.myTextView)).setText("Hello");
}

在我的普通 JVM 单元测试中,我想使用 Mockito 来测试这个方法。 例如,如果上面的方法是用 java 编写的,我可以这样做:

public void setViewsTest() {
    // Mock dependencies
    View view = Mockito.mock(View.class);
    TextView myTextView = Mockito.mock(TextView.class);
    when(fragment.getView()).thenReturn(view);
    when(view.findViewById(R.id. myTextView)).thenReturn(myTextView);

    // Call method
    fragment.setViews();

   // Verify the test
   verify(myTextView).setText("Hello");
}

在使用 Kotlin 的 kotlinx.android.synthetic 视图时如何进行类似的实现?

【问题讨论】:

    标签: android unit-testing kotlin mockito android-testing


    【解决方案1】:

    我认为Robolectric 是用于此类测试的更合适的工具。使用它,您可以更轻松地测试 Android 依赖于 JVM 的代码。

    例如,您的测试将如下所示:

    @Test
    fun `should set hello`() {
        val fragment = YourFragment()
    
        fragment.setViews()
    
        assertEquals(fragment.myTextView.getText().toString(), "Hello");
    }
    

    【讨论】:

      【解决方案2】:

      我也一直在寻找这个问题的解决方案,这就是我目前正在做的模拟视图以便能够验证它们。

      此解决方案不使用kotlinx.android.synthetic,因为我还没有找到避免“方法未模拟”异常的方法,而是使用Butterknife 方式。

      在活动或片段中:

      @BindView(R.id.my_text_view)
      internal lateinit var myTextView: TextView
      // ...
      fun setViews() {
          myTextView.text = "Hello"
      }
      

      在测试中:

      import com.nhaarman.mockito_kotlin.mock
      
      class MyActivityTest {
      
          private val underTest = MyActivity()
      
          @Before
          fun setUp() {
              underTest.myTextView = mock()
          }
      
          @Test
          fun setViews() {
              underTest.setViews()
      
              verify(underTest.myTextView).text = "Hello"
          }
      }
      

      【讨论】:

      • 这也是我目前的解决方案,但它并没有真正回答问题。我真的希望可以用 ktx 而不是 Butterknife 来做到这一点。希望尽快添加该功能
      【解决方案3】:

      我也有同样的问题。

      发现Kotlin extension 为视图/片段添加了一些功能。 假设 - 我有 Fragment - SampleFragment,其中 onViewCreated() 我在通货膨胀后访问了一些视图:

          override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
          super.onViewCreated(view, savedInstanceState)
          with(webView) {
              webViewClient = createWebClient()
          }
      }
      

      当然我的单元测试在 webViewClient = createWebClient() 上失败了

      那么,让我们看看我的片段中添加了哪些 kotlin 扩展(转到 Tools->Kotlin->Show Kotlin Byte Code 然后选择反编译)。

      public final class SampleFragment extends Fragment {
          ...
          private HashMap _$_findViewCache;
      
          public View _$_findCachedViewById(int var1) {
            if (this._$_findViewCache == null) {
               this._$_findViewCache = new HashMap();
            }
      
            View var2 = (View)this._$_findViewCache.get(var1);
            if (var2 == null) {
               View var10000 = this.getView();
               if (var10000 == null) {
                   return null;
               }
      
               var2 = var10000.findViewById(var1);
               this._$_findViewCache.put(var1, var2);
            }
      
            return var2;
         }
      

      现在,我们有了 HashMap 来存储我们所有的 ids->Views 键值对。 有两种可能的解决方案: 1. 窥探你的对象并返回正确的视图:

      @Mock lateinit var view: View
      @Mock lateinit var webView: WebView
      
      @Before
      fun setUp() {
          sampleFragment = spy(SampleFragment())
          doReturn(view).`when`(sampleFragment).view
          doReturn(webView).`when`(view).findViewById<WebView>(R.id.webView)
      }
      
      1. 使用反射(mockito Whitebox)初始化_$_findViewCache HashMap。

        var hashMap = java.util.HashMap() hashMap.put(R.id.webView, webView) Whitebox.setInternalState(sampleFragment, "_\$_findViewCache", hashMap)

      可能还有另一种更具体的 Kotlin 方法来避免这个问题?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-07-01
        • 1970-01-01
        • 2022-09-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-12
        相关资源
        最近更新 更多