Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/gwt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用异步调用测试GWTP presenter_Gwt_Testing_Mockito_Gwt Platform - Fatal编程技术网

使用异步调用测试GWTP presenter

使用异步调用测试GWTP presenter,gwt,testing,mockito,gwt-platform,Gwt,Testing,Mockito,Gwt Platform,我正在使用GWTP,添加了一个契约层来抽象Presenter和View之间的知识,我对GWTP的结果非常满意。 我正在用Mockito测试我的演示者 但随着时间的推移,我发现很难用测试来保持一个干净的演示者。 我做了一些重构工作来改进这一点,但我仍然不满意 我发现以下是问题的核心: 我的演示者通常需要异步调用,或者通常使用回调调用objects方法来继续我的演示者流(它们通常是嵌套的) 例如: this.populationManager.populate(new PopulationCal

我正在使用GWTP,添加了一个契约层来抽象Presenter和View之间的知识,我对GWTP的结果非常满意。 我正在用Mockito测试我的演示者

但随着时间的推移,我发现很难用测试来保持一个干净的演示者。 我做了一些重构工作来改进这一点,但我仍然不满意

我发现以下是问题的核心: 我的演示者通常需要异步调用,或者通常使用回调调用objects方法来继续我的演示者流(它们通常是嵌套的)

例如:

  this.populationManager.populate(new PopulationCallback()
  {
     public void onPopulate()
     {
        doSomeStufWithTheView(populationManager.get());
     }
  });
在测试中,我结束了对模拟PopulationManager对象的population()调用的验证。然后使用view()方法在doSomeStufWithView上创建另一个测试

但我很快发现这是一个糟糕的设计:任何更改或重构都会破坏我的许多测试,并迫使我从一开始就创建其他测试,即使演示者功能没有改变! 另外,我没有测试回调是否是我想要的

因此,我尝试使用mockito-doAnswer方法来不破坏演示者测试流程:

doAnswer(new Answer(){
     public Object answer(InvocationOnMock invocation) throws Throwable
     {
        Object[] args = invocation.getArguments();
        ((PopulationCallback)args[0]).onPopulate();
        return null;
     }
 }).when(this.populationManager).populate(any(PopulationCallback.class));
我考虑了代码,使其不那么冗长(并且在内部不太依赖于arg位置):

因此,在模拟populationManager的同时,我仍然可以测试演示者的流程,基本上如下所示:

@Test
public void testSomeStuffAppends()
{
  // Given
  doAnswer(new PopulationCallbackAnswer())
  .when(this.populationManager).populate(any(PopulationCallback.class));

  // When
  this.myPresenter.onReset();

  // Then
  verify(populationManager).populate(any(PopulationCallback.class)); // That was before
  verify(this.myView).displaySomething(); // Now I can do that.
}
我想知道这是否是对doAnswer方法的一个很好的使用,或者它是否是一种代码气味,是否可以使用更好的设计

通常,我的演示者倾向于使用其他对象(比如一些中介模式)并与视图交互。我有一些演示者,有几百行(约400行)代码

再说一次,这是糟糕设计的证明,还是演示者冗长(因为它使用其他对象)是正常的

有没有人听说过使用GWTP并干净地测试其演示者的项目

我希望我的解释是全面的

先谢谢你


PS:我对Stack Overflow还很陌生,加上我的英语还不够好,如果我的问题需要改进,请告诉我。

你可以使用
ArgumentCaptor


更多详情,请查看此链接

如果我理解正确,您是在询问有关设计/架构的问题

这不应该算作答案,这只是我的想法

如果我遵循了代码:

    public void loadEmoticonPacks() {
    executor.execute(new Runnable() {
        public void run() {
            pack = loadFromServer();
            savePackForUsageAfter();
        }
    });
}
我通常不指望执行器,而只是通过加载和保存来检查方法是否完成了具体的工作。所以这里的执行器只是防止UI线程中长时间操作的工具

如果我有类似于:

accountManager.setListener(this);
....
public void onAccountEvent(AccountEvent event) {
....
}
我将首先检查我们是否订阅了事件(并取消了某些事件的订阅),同时检查AccountEvent上的
是否符合预期场景

UPD1.在示例1中,最好是提取方法
loadfromserver和save
,并检查它是否未在UI线程上执行,以及检查它是否按预期执行了所有操作


UPD2。最好使用像Guava总线这样的框架来处理事件。

我们在演示者测试中也使用了这种doAnswer模式,通常效果很好。不过有一点需要注意:如果您这样测试它,那么实际上是在删除调用的异步性质,即在服务器调用启动后立即执行回调

这可能导致未发现的比赛条件。要检查这些,您可以将这一过程分为两步:调用服务器时,answer方法只保存回调。然后,在测试中适当的时候,在答案上调用flush()或onSuccess()之类的函数(我建议为此创建一个实用程序类,在其他情况下可以重用),这样就可以控制何时真正调用结果的回调

accountManager.setListener(this);
....
public void onAccountEvent(AccountEvent event) {
....
}