【问题标题】:MVP, testing, and private methods [closed]MVP、测试和私有方法
【发布时间】:2012-10-04 02:49:49
【问题描述】:

我已切换到 MVP 架构并正在尝试对其进行测试。我对如何构建我的 Presenter 有一些疑问。

public class Presenter
{
    public void onResume()
    {
        doA();
        doB();
        doC();
    }

    protected void doA() {};
    protected void doB() {};
    protected void doC() {};
}

public class MyScreen implements MyScreenView
{
    private Presenter presenter;

    public MyScreen()
    {
        presenter = new Presenter(this);
    }

    public OnResume()
    {
        presenter.OnResume();
    }
}

在上面的代码中,当视图被恢复时,视图只是简单地调用了presenter OnResume()。演示者在内部调用 3 个方法,doA()、doB() 和 doC() 来做它必须做的任何事情。

或者,我可以直接在视图中调用 doA()、doB() 和 doC(),如下所示:

public class Presenter
{
    public void doA() {};
    public void doB() {};
    public void doC() {};
}

public class MyScreen implements MyScreenView
{
    private Presenter presenter;

    public MyScreen()
    {
        presenter = new Presenter(this);
    }

    public OnResume()
    {
        presenter.doA();
        presenter.doB();
        presenter.doC();
    }
}

我的问题是,测试第二个解决方案对我来说更容易,因为演示者被完全分解为 3 个独立的个人责任公共方法,我可以分别为 doA、doB 和 doC 编写测试,而不是一个单一的测试解决方案1的presenter.onResume()方法。

在第一个解决方案中,我必须为 onResume() 编写测试,它同时负责调用这 3 个方法。这意味着它更难测试,因为它比调用其他私有函数的函数更容易测试个人责任的较小函数。然而,在我看来,第二个解决方案并不像一个好的 MVP,因为它似乎知道演示者在做什么,只是不让演示者做它在第一个解决方案的 onResume() 方法中应该做的事情。

【问题讨论】:

  • 永远不要在 stackoverflow 上征求意见。这是解决问题的保证。当然,值得赞成或反对的一切都是意见,但那是另一回事。

标签: java unit-testing tdd mvp


【解决方案1】:

首先在 My Screen 类中使演示者可注入

public class MyScreen implements MyScreenView
{
    private presenter;

    public MyScreen()
    {
        presenter = this(new Presenter());
    }

    public MyScreen(Presenter p) 
    {
        presenter = p;
    }

    public OnResume()
    {
        presenter.OnResume();
    }
}

现在您可以通过注入模拟来测试 MyScreen 的行为。

Presenter mockP = Mock(Presenter.class);
MyScreen target = new MyScreen(mockP);
target.OnResume();
verify(mockP).doA();
verify(mockP).doB();
verify(mockP).doC();

在完全独立的测试中,您可以测试演示者:

Presenter presenter = new Presenter();
presenter.onResume();
assertEquals("some State that should be true after calling on resume", presenter.getSomeMagicState());

不要测试 onResume 调用 doA、doB 和 doC,通过检查演示者的状态来测试方法的行为。

如果 doX 所做的事情变得复杂,请将其提取到一个单独的类中,对其进行测试,将其注入演示者并测试它是否被调用。

【讨论】:

    【解决方案2】:

    如果您将 MyScreen 类更改为

    public class MyScreen implements MyScreenView
    {
        private presenter;
    
        public MyScreen()
        {
            presenter = new Presenter();
        }
    
        public MyScreen(Presenter p) 
        {
            presenter = p;
        }
    
        public OnResume()
        {
            presenter.OnResume();
        }
    }
    

    然后你有一个生产构造函数,它创建一个新的 Presenter 和一个用于测试的便利构造函数,因此你可以使用 Mock Presenter 实例化它。我更喜欢 Mockito(内存中的代码......)

    Presenter mockP = Mock(Presenter.class);
    MyScreen target = new MyScreen(mockP);
    target.OnResume();
    verify(mockP).doA();
    verify(mockP).doB();
    verify(mockP).doC();
    

    在这里,您可以使用 Mock Presenter 创建一个新的 MyScreen。当您对各种方法调用 verify 时,如果从未在 mock 上调用该方法,您的测试将失败。因此,您实际上是在编写一个测试,断言如果您在 MyScreen 类上调用 OnResume,效果就是在其 Presenter 字段上调用 ​​doA、doB 和 doC。

    您可以在验证方法被调用时指定您期望的参数。并且您可以对 mockP 的方法进行存根,以便它在特定场景中返回已知结果。


    顺便说一句

    public OnResume()
        {
            presenter.OnResume();
        }
    

    恕我直言,这两个选项是更好的选择,因为这样您就可以更改 presenter.OnResume() 方法的功能,而无需更改 MyScreen 类。

    【讨论】:

    • hrm....如果 doA() 是私有的,我可以调用 verify(mockP).doA() 吗?
    • 否,那么您将验证 Presenter 的 onResume 方法是否被调用。当您测试 Presenter 类时,您可以测试如果 onResume 被称为这三个 do 方法的东西..er... ... do 已完成。我感觉 PowerMock 可以处理私有方法,但我从未使用过 powerMock,所以很容易出错
    猜你喜欢
    • 1970-01-01
    • 2020-08-03
    • 1970-01-01
    • 2014-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多