我有以下几点:
我有两个简单的测试,当单独运行时,它们都通过了。但是,(在Eclipse中)在彼此之后运行它们时,第二个操作总是失败,并出现以下错误:
想要但没有被调用: exService.exampleServiceMethod()。实际上,这个模拟没有任何交互作用。
我对服务进行了如下注释:@GwtMock exService;
需要注意的是,调用异步服务的ExampleLogic类在自己的类中创建服务。我可以通过设置测试类中的异步服务来使其工作,就像您在示例中看到的那样。但我只需要莫基托的@Mock。
它可以工作,因此这个问题更多的是出于好奇,而且只是一点点的实用(因为只为了测试而没有必要为异步服务设置一个setter )。
所以问题是:
为什么是这样?
其他问题:
对此有什么可做的吗?你推荐其他的测试方法吗?
希望有任何的GWT专家,可以帮助我!
使用:
JUnit 4.13
GwtMockito 1.1.9 (以及下面的Mockito : 0.9.2)
ExampleLogic.java (使用异步服务执行服务器调用的类)
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)
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,用于创建异步实例)
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 ()这是错误所在
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);
}
}发布于 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选项的快速摘要:
https://stackoverflow.com/questions/70589292
复制相似问题