Android 使Android Studio单元测试(以mvp模式为列)

32 篇文章 5 订阅
16 篇文章 0 订阅

第一步:build.gradle文件添加测试相关依赖

dependencies { 
    testImplementation 'junit:junit:4.12'
    testImplementation 'org.mockito:mockito-core:2.19.0'
    testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0'//mock()
    testImplementation 'org.mockito:mockito-inline:2.13.0'//适配单元测试时,不能调用final类
...
}

第二步新建测试类(项目中存在的类)

BasePresenter:
package com.example.test

abstract class BasePresenter<V> {
  protected var view: V? = null

  fun attachView(view: V) {
    this.view = view
  }

  fun detachView() {
    this.view = null
  }
}
Recipe:
package com.example.test

class Recipe(var id : String ="",var title :String = "",var imageUrl : String ="",var sourceUrl : String ="",var isFavorited : Boolean = false) 
RecipeRepository:
package com.example.test

interface RecipeRepository {
  fun addFavorite(item: Recipe)
  fun removeFavorite(item: Recipe)
  fun getFavoriteRecipes(): List<Recipe>
  fun getRecipes(query: String, callback: RepositoryCallback<List<Recipe>>)
}

interface RepositoryCallback<in T> {
  fun onSuccess(t: T?)
  fun onError()
}
SearchResultsPresenter:
package com.example.test

/**
 * JunitTestClass
 */
class SearchResultsPresenter(private val repository: RecipeRepository) :
    BasePresenter<SearchResultsPresenter.View>() {
  private var recipes: List<Recipe>? = null

  fun search(query: String) {
    view?.showLoading()

    repository.getRecipes(query, object : RepositoryCallback<List<Recipe>> {
      override fun onSuccess(recipes: List<Recipe>?) {
        this@SearchResultsPresenter.recipes = recipes
        if (recipes != null && recipes.isNotEmpty()) {
          view?.showRecipes(recipes)
        } else {
          view?.showEmptyRecipes()
        }
      }

      override fun onError() {
        view?.showError()
      }
    })
  }

  fun addFavorite(recipe: Recipe) {
    recipe.isFavorited = true

    repository.addFavorite(recipe)

    val recipeIndex = recipes?.indexOf(recipe)
    if (recipeIndex != null) {
      view?.refreshFavoriteStatus(recipeIndex)
    }
  }


  fun removeFavorite(recipe: Recipe) {
    repository.removeFavorite(recipe)
    recipe.isFavorited = false
    val recipeIndex = recipes?.indexOf(recipe)
    if (recipeIndex != null) {
      view?.refreshFavoriteStatus(recipeIndex)
    }
  }

  interface View {
    fun showLoading()
    fun showRecipes(recipes: List<Recipe>)
    fun showEmptyRecipes()
    fun showError()
    fun refreshFavoriteStatus(recipeIndex: Int)
  }
}

第三步:给presenter新建测试类

1>、windows快捷键:ctrl+shift+T(也可鼠标右键->go to->Test);

2>、接着有测试类会让你选择,没有的->create new test...;

3>

4>新建成功

第四步:编写测试方法

1>verify方法(@Before将在@Test等方法之前调用)

class SearchResultsPresenterTest{
    private lateinit var repository: RecipeRepository
    private lateinit var presenter: SearchResultsPresenter
    private lateinit var view: SearchResultsPresenter.View

    @Before //最先调用(初始化)
    fun setup() {
        repository = mock()
        view = mock()
        presenter = SearchResultsPresenter(repository)
        presenter.attachView(view)
    }

    @Test
    fun search_callsShowLoading() {
        presenter.search("eggs")
//        verify(view).showLoading()//验证搜索时showLoading会不会被调用到
        verify(view).showEmptyRecipes()//验证showEmptyRecipes会不会被调用到
//        verify(view).showRecipes(mock())//验证showRecipes会不会被调用到
    }
}

如果verify方法验证了这次运行未调用此方法,运行后将会抛出错误,便于我们验证是否运行后调用该方法(如果调用了,日志没有反应)

同时刚才我们的coverage运行结果可以直接查看方法被调用的情况

2、doAnswer方法(插桩):

   @Test
    fun search_callShowRecipes() {
        val recipe = Recipe("id", "title", "imageUrl", "sourceUrl", false)
        val recipes = listOf(recipe)

        doAnswer {//执行相应的方法(getRecipes)并拿到回调(Stubbing--插桩)
            val callback: RepositoryCallback<List<Recipe>> = it.getArgument(1)
//            callback.onSuccess(recipes)//此时以下的verify将会全部通过
            callback.onError()//这里也可以用onError()方法验证(此时下面的verify(view).showRecipes(eq(recipes))将会抛出错误)
        }.whenever(repository).getRecipes(eq("eggs"), any())

        presenter.search("eggs")

        verify(repository).getRecipes(eq("eggs"), any())
        verify(view).showRecipes(eq(recipes))

    }

通过doAnswer方法和verify方法,我们可以验证代码是否正确调用了正确的方法(行为验证)

3:Assert 方法:

    @Test
    fun addFavorite_shouldUpdateRecipeStatus() {
        val recipe = Recipe("id", "title", "imageUrl", "sourceUrl", false)
        presenter.addFavorite(recipe)
        //状态验证,assertThat(T actual, Matcher<? super T> matcher)左边为待验证的字段,右边为匹配器,
        // is是kotlin关键字,所以'is'。如果验证字段不同将会抛出错误。
        Assert.assertThat(recipe.isFavorited, CoreMatchers.`is`(false))
    }
状态验证,assertThat(T actual, Matcher<? super T> matcher)左边为待验证的字段,右边为匹配器,is是kotlin关键字,所以'is';
  @Test
    fun removeFavorite_shouldUpdateRecipeStatus() {
        val recipe = Recipe("id", "title", "imageUrl", "sourceUrl", true)
        presenter.removeFavorite(recipe)
        Assert.assertThat(recipe.isFavorited, CoreMatchers.`is`(false))
    }
SearchResultsPresenterTest
package com.example.test

import com.nhaarman.mockitokotlin2.*
import org.hamcrest.CoreMatchers
import org.junit.Assert
import org.junit.Before
import org.junit.Test

class SearchResultsPresenterTest{
    private lateinit var repository: RecipeRepository
    private lateinit var presenter: SearchResultsPresenter
    private lateinit var view: SearchResultsPresenter.View

    @Before //最先调用(初始化)
    fun setup() {
        repository = mock()
        view = mock()
        presenter = SearchResultsPresenter(repository)
        presenter.attachView(view)
    }

    @Test
    fun search_callsShowLoading() {
        presenter.search("eggs")
//        verify(view).showLoading()//验证搜索时showLoading会不会被调用到
        verify(view).showEmptyRecipes()//验证showEmptyRecipes会不会被调用到
//        verify(view).showRecipes(mock())//验证showRecipes会不会被调用到
    }

    @Test
    fun search_callShowRecipes() {
        val recipe = Recipe("id", "title", "imageUrl", "sourceUrl", false)
        val recipes = listOf(recipe)

        doAnswer {//执行相应的方法(getRecipes)并拿到回调(Stubbing--插桩)
            val callback: RepositoryCallback<List<Recipe>> = it.getArgument(1)
            callback.onSuccess(recipes)//此时以下的verify将会全部通过
//            callback.onError()//这里也可以用onError()方法验证(此时下面的verify(view).showRecipes(eq(recipes))将会抛出错误)
        }.whenever(repository).getRecipes(eq("eggs"), any())

        presenter.search("eggs")

        verify(repository).getRecipes(eq("eggs"), any())
        verify(view).showRecipes(eq(recipes))

    }

    @Test
    fun search_error_callShowError() {
        doAnswer {
            val callback: RepositoryCallback<List<Recipe>> = it.getArgument(1)
            callback.onError()
        }.whenever(repository).getRecipes(eq("eggs"), any())

        presenter.search("eggs")

        verify(repository).getRecipes(eq("eggs"), any())
        verify(view).showError()
    }

    @Test
    fun addFavorite_shouldUpdateRecipeStatus() {
        val recipe = Recipe("id", "title", "imageUrl", "sourceUrl", false)
        presenter.addFavorite(recipe)
        //状态验证,assertThat(T actual, Matcher<? super T> matcher)左边为待验证的字段,右边为匹配器,
        // is是kotlin关键字,所以'is'。如果验证字段不同将会抛出错误。
        Assert.assertThat(recipe.isFavorited, CoreMatchers.`is`(false))
    }

    @Test
    fun removeFavorite_shouldUpdateRecipeStatus() {
        val recipe = Recipe("id", "title", "imageUrl", "sourceUrl", true)
        presenter.removeFavorite(recipe)
        Assert.assertThat(recipe.isFavorited, CoreMatchers.`is`(false))
    }

}

参考连接:

https://juejin.im/post/6844903848272723975#heading-14

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Studio 是一个开发 Android 应用程序的集成开发环境(IDE),而 MVP(Model-View-Presenter)是一种软件架构模式,用于分离应用的业务逻辑、用户界面和数据。 在 Android Studio 中使用 MVP 架构可以帮助开发者更好地组织和管理代码,提高应用的可维护性和可测试性。下面是使用 MVP 架构的一般步骤: 1. Model: 定义应用程序的数据模型,负责获取和处理数据。这可以是从网络、数据库或其他来源获取数据的地方。 2. View: 负责展示用户界面,并与用户进行交互。它不处理任何业务逻辑,只负责将用户的操作传递给 Presenter,并显示 Presenter 返回的结果。 3. Presenter: 充当 View 和 Model 之间的中间人,负责处理业务逻辑。它从 Model 获取数据,并将结果传递给 View 进行展示。同时,它也接收来自 View 的用户操作,并根据需要更新 Model。 在 Android Studio 中使用 MVP 架构,你可以创建三个不同的包来分别存放 Model、View 和 Presenter 的代码。然后,根据需要在相应的类中添加所需的方法和逻辑。 使用 MVP 架构可以将应用程序的不同部分解耦,使得每个部分都可以独立开发和测试。这有助于提高代码的可维护性和可测试性,同时也使得团队开发更加高效。 希望这个简单的介绍能够帮助你了解如何在 Android Studio 中使用 MVP 架构。如果你有更多的问题,可以继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值