首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GwtMockito:在测试类中使用异步服务时,单个测试通过,多个测试失败。(GwtMock-和GWT.create相关)

GwtMockito:在测试类中使用异步服务时,单个测试通过,多个测试失败。(GwtMock-和GWT.create相关)
EN

Stack Overflow用户
提问于 2022-01-05 07:38:04
回答 1查看 51关注 0票数 0

我有以下几点:

  • ExampleLogic.java (使用异步服务执行服务器调用的类)
  • ExampleServiceAsync.java (Interfaceála GWT)
  • ExampleService.java (Interfaceála GWT,用于创建异步实例)
  • ExampleLogicTest (,这是错误出现的地方,)

我有两个简单的测试,当单独运行时,它们都通过了。但是,(在Eclipse中)在彼此之后运行它们时,第二个操作总是失败,并出现以下错误:

想要但没有被调用: exService.exampleServiceMethod()。实际上,这个模拟没有任何交互作用。

我对服务进行了如下注释:@GwtMock exService;

需要注意的是,调用异步服务的ExampleLogic类在自己的类中创建服务。我可以通过设置测试类中的异步服务来使其工作,就像您在示例中看到的那样。但我只需要莫基托的@Mock

它可以工作,因此这个问题更多的是出于好奇,而且只是一点点的实用(因为只为了测试而没有必要为异步服务设置一个setter )。

所以问题是:

为什么是这样?

其他问题:

对此有什么可做的吗?你推荐其他的测试方法吗?

希望有任何的GWT专家,可以帮助我!

使用:

JUnit 4.13

GwtMockito 1.1.9 (以及下面的Mockito : 0.9.2)

ExampleLogic.java (使用异步服务执行服务器调用的类)

代码语言:javascript
复制
import com.google.gwt.user.client.rpc.AsyncCallback;

public class ExampleLogic {
  public boolean callFailed; // public to simplify example
  public boolean returnVal; // public to simplify example
  private ExampleServiceAsync exampleService;
  
  public void setExampleService(ExampleServiceAsync exampleService) {
    this.exampleService = exampleService;
  }

  public void exampleCallToService() {
    if (exampleService == null) {
      exampleService = ExampleService.Util.getInstance(); // Problem arises here.
      // I suppose GwtMockito is reusing the old one even though GwtMockito.tearDown() is called.
      // That's why the second fails with the comment "There were zero interactions with this mock".
      // It is actually using the first still. Why is that so and how can I make it use the second?
    }
    
    exampleService.exampleServiceMethod(new AsyncCallback<Boolean>() {
      
      @Override
      public void onSuccess(Boolean result) {
        callFailed = false;
        returnVal = result;
      }
      
      @Override
      public void onFailure(Throwable caught) {
        callFailed = true;
      }
    });
  }
}

ExampleServiceAsync.java (Interfaceála GWT)

代码语言:javascript
复制
import com.google.gwt.http.client.Request;
import com.google.gwt.user.client.rpc.AsyncCallback;

public interface ExampleServiceAsync {
  public Request exampleServiceMethod(AsyncCallback<Boolean> callback);
}

ExampleService.java (Interfaceála GWT,用于创建异步实例)

代码语言:javascript
复制
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.RemoteService;

public interface ExampleService extends RemoteService {
  public static class Util {
    private static ExampleServiceAsync instance = null;
    public static ExampleServiceAsync getInstance(){
      if (instance == null) {
        instance = (ExampleServiceAsync) GWT.create(ExampleService.class);
      }
      
      return instance;
    }
  }
  
  boolean exampleServiceMethod();
}

seen) ExampleLogicTest ()这是错误所在

代码语言:javascript
复制
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwtmockito.GwtMock;
import com.google.gwtmockito.GwtMockito;
import com.google.gwtmockito.GwtMockitoTestRunner;

@RunWith(GwtMockitoTestRunner.class)
public class ExampleLogicTest {

  @GwtMock ExampleServiceAsync exService;
  // @Mock ExampleServiceAsync exService; // Can be used if the service is set manually
  @Captor ArgumentCaptor<AsyncCallback<Boolean>> callbackCaptor;
  ExampleLogic exLogic;

  @Before
  public void init() {
    GwtMockito.initMocks(this); // Doesn't make any difference to comment/uncomment.
    exLogic = new ExampleLogic();
//    exLogic.setExampleService(exService); // Uncommenting this will make both tests pass in a single run. Otherwise the second to run will always fail. Or running separately they'll pass.
  }

  @After
  public void tearDown() {
    GwtMockito.tearDown(); // Doesn't make any difference to comment/uncomment.
  }

  @Test
  public void test1_SuccessfulCall() {
    exLogic.exampleCallToService();
    Mockito.verify(exService).exampleServiceMethod(callbackCaptor.capture());
    AsyncCallback<Boolean> callback = callbackCaptor.getValue();
    callback.onSuccess(true);
    assertFalse(exLogic.callFailed);
    assertTrue(exLogic.returnVal);
  }

  @Test
  public void test2_FailedCall() {
    exLogic.exampleCallToService();
    Mockito.verify(exService).exampleServiceMethod(callbackCaptor.capture());
    AsyncCallback<Boolean> callback = callbackCaptor.getValue();
    callback.onFailure(new Throwable());
    assertTrue(exLogic.callFailed);
    assertFalse(exLogic.returnVal);
  }

}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-06 17:44:42

如果(exampleService == null) { exampleService = ExampleService.Util.getInstance();//出现问题。//我认为GwtMockito正在重用旧的,即使调用了GwtMockito.tearDown()。//这就是为什么第二个注释“与这个模拟没有任何交互”失败的原因。//它实际上使用的是第一个空号。为什么是这样,如何使它使用第二个?}公共静态类Util {私有静态ExampleServiceAsync实例=空;公共静态ExampleServiceAsync getInstance(){ if (实例==空){getInstance= (ExampleServiceAsync) GWT.create(ExampleService.class);}返回实例;}}

你的猜测是正确的-这是你的问题。由于这个Util.instance字段是静态的,并且在测试完成时没有任何东西会取消它,所以下一个对Util.getInstance()的调用必须始终返回相同的值,所以模拟永远不会被创建。

考虑的一些可能的备选办法:

首先,以这种方式创建服务非常便宜,可能所有的服务调用都将被重做为静态方法,因此创建服务或保持实例几乎没有实际成本。这意味着您可以在每次调用该方法时创建一个新的服务实例,也许每次调用任何服务方法时都是如此。如果状态是重要的要共享的,或者创建的成本很高--至少在这里共享的代码中,这两种情况都不是真的,那么就应该使用单例。

由此,您也可以直接使用GWT.create(.)所需的服务,而不是包含实例的Util类型。

或者,假设您确实希望控制对实例的访问(可能是为了允许在创建服务时对服务进行自定义配置,等等),而不是在类中使用静态字段来保持此功能,那么可以考虑使用一个常规字段,这样就可以将一个新的持有者作为每个测试的一部分进行实例化。如果您不想要某种完整的DI工具,您仍然可以创建一个实例来提供这些对象。有一个只测试的方法,在tearDown()等期间取消实例。

依赖注入("DI")工具的GWT选项的快速摘要:

  • 杜松子酒:在GWT2中,"gin+盖斯“非常流行,但是不再被维护,并且不兼容J2CL (可以处理大量GWT2输入的另一个编译器),但是非常灵活。Gin是Guice特性的一个子集,可以在GWT中工作。
  • Dagger2是另一种选择,但并不是专为在GWT中工作而构建的。有许多示例演示了GWT2+Dagger2,下面的例子反映了它们的docs https://github.com/ibaca/gwt-dagger2-coffee
  • 二雷在其其他特性中可以充当CDI容器,但也添加了许多其他特性--几乎可以肯定地说,这对您来说太过了。我不认为这是今天开始的一个新项目。
  • 冷藏室是另一个选项,专门为在j2cl中工作而构建的,但仍在进行中(尽管工件作为v0.1发布到maven central )。它的设计似乎只是Errai的CDI特性,而且更加轻量级。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70589292

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档