将视图的引用传递给MVP模式中的Presenter是一种不好的做法吗?

时间:2018-05-25 11:40:18

标签: android unit-testing mvp android-mvp

我有一个关于Android的大项目,Kotlin使用MVP模式,我开始努力进行单元测试(测试演示者模拟视图界面)。原因是我在演示者中将视图引用传递给我的函数,并且必须嘲笑它​​们真的很糟糕,例如:

我的代码如下:

class MainActivity : Activity(), MainActivityView {

    @BindView(R.id.numberTV)
    lateinit var numberTV : AppCompatTextView

    private val mainActivityPresenter = MainActivityPresenter(this)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        mainActivityPresenter.onCreate()
    }

    override fun showNumber() {
        mainActivityPresenter.showNumber(numberTV, 22)
    }

}

interface MainActivityView {
    fun showNumber()
}

class MainActivityPresenter(private val mainActivityView: MainActivityView) {
    fun showNumber(numberTV: AppCompatTextView, number: Int) {
        numberTV.text = if (number < 0) {
            "Not compatible"
        } else if (number < 10) {
            number.toString()
        } else {
            "9+"
        }
    }

    fun onCreate() {
        mainActivityView.showNumber()
    }
}

我目前的问题是,当我在单元测试中使用Mockito测试函数showNumber(AppCompatTextView, Int)时,我应该模拟视图以通过测试(因为它可以&# 39; t为null)。

哪一个更适合在这里进行单元测试?

我的想法是:

  1. numberTV: AppCompatTextView抓取MainActivityPresenter,例如mainActivityPresenter.getBindViews().mainIV
  2. 仅从演示者返回文本逻辑("Not compatible"number.toString()"9+"),尽管有时需要在视图之外执行逻辑(2 +)
  3. 你会做什么?

    修改

    我想指出,不将任何View传递给演示者,可能是异步调用的问题。

    示例:使用Glide设置图像:

    internal fun showImageAccordingToCache(cachedSplashScreenUri: String?, mainImageView: ImageView) {
        Glide.with(context)
                /**
                 * Save in cache, but we say to load it from cache. Otherwise it will throw an error
                 */
                .setDefaultRequestOptions(defaultDiskStrategy()
                        .onlyRetrieveFromCache(true))
                .load(cachedSplashScreenUri)
                .listener(object : RequestListener<Drawable> {
                    override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
                        /**
                         * And when that error is thrown, we preload the image for the next time.
                         */
                        activityViewPresenter.showLogo()
                        loadImageInCache(cachedSplashScreenUri)
                        return true
                    }
    
                    override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
                        return false
                    }
                })
                .into(mainImageView)
    }
    

2 个答案:

答案 0 :(得分:1)

我认为您不应该将视图传递给演示者。您的演示者应该调用mainActivityView方法来显示所需的数据。这应该是mainAcitivityView

中的方法
override fun showNumber(number: String) {
    numberTV.text = number
}

你应该从你的演示者这样称呼这个

fun onCreate() {
   showNumber(22)
}

fun showNumber(number: Int) {
    numberString:String = if (number < 0) {
        "Not compatible"
    } else if (number < 10) {
        number.toString()
    } else {
        "9+"
    }
    mainActivityView.showNumber(numberString:String)
}

答案 1 :(得分:1)

在演示者中设置界面视图是正常的。在您的情况下,MainActivityView是表示您的Activity必须遵守的合同的接口。您通常会使用dagger将其注入演示者,在演示者的构造函数中(您已经在做什么)传递该视图。

现在,这不常见:

 fun showNumber(numberTV: AppCompatTextView, number: Int) {
        numberTV.text = if (number < 0) {
            "Not compatible"
        } else if (number < 10) {
            number.toString()
        } else {
            "9+"
        }
    }

现在主持人知道“Android SDK组件”,这不是一件好事。在这种情况下,你应该做的是:

 fun showNumber(number: Int) {
        if (number < 0) {
            mainActivityView.setNumberText("Not compatible");
        } else if (number < 10) {
            mainActivityView.setNumberText(number.toString());
        } else {
            mainActivityView.setNumberText("9+");
        }
    }

要测试这个,你会模拟视图,看看是否依赖于数字实际调用了这些方法。(在java中)。

@Mock
MainActivityView view;

@Test
public fun shouldShowCorrectNumber() {

    int number = 10;
    presenter.showNumber(number);
    verify(view).showNumber("9+");
}

对于异步调用,我在使用Glide库时通常会看到它在活动中使用,而不是在演示者中使用。例如,其他类型的异步调用可能会出现在其他层中。我通常会在Interactor层中看到网络调用,并对演示者进行回调:

相关问题