gwt 测试

GWT是Google开发的框架,用于使用Java编程语言构建支持AJAX的Web应用程序。 它包括:

  1. 用于创建GUI的API(类似于Swing),用于处理Web浏览器的文档对象模型(DOM)。
  2. Java到JavaScript的编译器。
  3. 用于运行和调试GWT应用程序的环境。

这种方法具有一些优点:

  • 假设您了解Java,则无需学习新的编程语言。
  • 您可以构建支持AJAX的Web应用程序,而无需编写JavaScript或HTML。
  • 一切都是用Java编写的,因此可以使用Java的高级开发工具,包括调试和重构支持。
  • GWT使开发人员免受浏览器特性的影响

最后,由于所有内容都在Java中(甚至MVC模式的View部分),我们应该能够轻松创建UI测试。 本文探讨了一些方法。

1.第一次尝试

1.1使用TDD的 GWT

我们将从一个简单的示例开始:我们要显示一个文本输入字段,一个按钮和一个标签。 当我们单击按钮时,用户输入的文本字段内容将放置在标签中。 相应的测试(在JUnit 4中 )将是:

1 @Test
2public void testClick () {3    GwtExample view = new GwtExample();
4    Assert . assertNull (view. getLabel (). getText());
5    view. getTextBox().setText ("my text");
6    // creation of a basic "click"  event
7    NativeEvent event = Document. get().createClickEvent (0, 0, 0, 0, 0, false, false, false, false);     // dispatch de l'évènement     DomEvent.fireNativeEvent(event, view.getButton());
8    Assert . assertEquals ("my text", view. getLabel().getText());
9 }

然后,我们可以编写相应的View代码:

1public class GwtExample extends Composite {
2    private Label label;
3    private TextBox textBox;
4    private Button button;
5
6    public GwtExample() {
7       FlowPanel fp = new FlowPanel();
8       textBox = new TextBox();
9       fp.add(textBox);
10      button = new Button (" validate ");
11      fp.add(button);
12      button.addClickHandler( new ClickHandler() {
13
14          public void onClick(ClickEvent event) {
15              label.setText(textBox.getText());
16
17          }
18      });
19      label = new Label("init");
20      fp.add(label);
21      initWidget(fp);
22   }
23
24   public Label getLabel() { return label; }
25   public TextBox getTextBox() { return textBox; }
26   public Button  getButton() { return button; }
27 }

最后,我们启动前面的JUnit测试:

1 java.lang . ExceptionInInitializerError ...
2 Caused by: java. lang . UnsupportedOperationException : ERROR: GWT. create () is only usable in
3 client code!  It cannot be called, for example, from server code.  If you are running a unit
4 test, check that your test case extends GWTTestCase and that GWT. create () is not called
5 from within an initializer or constructor.
6   at com. google.gwt.core.client.GWT.create (GWT. java : 85 )
7   at com. google.gwt.user.client.ui.UIObject .(UIObject. java : 140 )
8   ... 23 more

上面的错误意味着在标准JVM中不使用GWT类。 它们只有在将它们编译为JavaScript并在浏览器中执行后才能工作。

1.2一些现有的解决方案

1.2.1 GWTTestCase

GWT提供了一个用于执行单元测试的类,称为GWTTestCase,但是它受到许多限制:

  • 本机事件的管理仅从GWT 1.6开始实施。 GWTTestCase不允许按照以前的版本以有效的方式测试View部件。
  • 缓慢。 实际上,此类启动了一个屏蔽的HostedMode(GWT的开发环境),这意味着它需要几秒钟的时间来初始化自身。
  • 查找文件。 单元测试必须由GWT编译。 因此,必须由MyApp.gwt.xml文件引用它们。 这使应用程序的启动和打包变得相当复杂,尤其是使用Maven时 。

此外,使用GWTTestCase和GWTTestSuite极大地限制了对Java API的访问:单元测试必须与GWT编译器兼容(该编译器负责将Java UI代码编译为JavaScript)。 这意味着,例如,不可能使用Java反射。 因此,无法使用Unitils或Easymock等测试库。

Java类JavaScript中模拟名单可在这里 。

GWT 2.0对GWTTestCase进行了改进,因为该类不再使用本机库来运行测试。 使用HtmlUnit代替托管模式使用的浏览器。 在GWT 2中,GWTTestCase与平台无关。 但是GWTTestCase仍然存在一些局限性:测试执行缓慢,并且不可能使用标准的测试框架。

1.2.2使用界面

测试GWT应用程序的一种解决方案是在测试时不使用GWT对象,而是将所有GWT对象替换为可在标准JVM中工作的模拟对象。 然而,该解决方案带来了很大的不便。 由于GWT对象不是接口,而是具体的类,因此我们将必须修改应用程序的代码,使其使用接口(您可以在此处找到示例) 。 该解决方案影响我们应用程序的设计。

1.3问题的核心

为了前进,我们调查了Google为什么在标准JVM中阻止GWT类的执行。 原因很简单:这些类的大部分代码使用JSNI代码。 JSNI代码以以下方式显示:

1public static native void alert( String msg) /*-{   $wnd.alert(msg); }-*/; 

这是本机功能。 这意味着在执行期间,JVM将尝试执行与DLL(或.so)同名的函数。 将这些类编译为JavaScript后,该方法将替换为/ *和* /中的代码。 这就是我们无法使用非JavaScript在标准JVM中执行的原因。

此外,部分GWT行为不是用Java实现,而是用JavaScript(或浏览器HTML呈现系统)实现。 即使我们成功解决了本机方法的问题,我们也必须找到解决方案以重新实现此行为。

2. Gwt-Test-Utils框架

2.1目的

我们有效实现GWT测试的目标如下:

  • 我们的测试课程不需要任何烦人的加载时间。
  • 我们应该能够直接操作GWT类,而无需使项目变得更加复杂的中间接口。
  • 我们应该能够使用所有Java标准API,特别是自省Java API(以使用诸如Unitils之类的工具)。
  • 我们想要一些轻巧且与Maven兼容的东西。

2.2“ gwt-test-utils”框架

在客户项目期间,我们开发了一个框架来满足我们的目标。

我们设计了一个测试框架来修改GWT类,而无需开发人员进行任何其他工作。 它从对GWT对象的类的字节码的“热”修改开始,以用Java方法替换本机JSNI方法,如下图所示:

注意:框架技术实现的介绍不属于本文范围。 我们将专注于其用法。

我们已将此框架作为一个开源项目Gwt-Test-Utils发布 ,以便任何人都可以使用它。

2.3使用框架

我们将从编写一个简单的Junit 4测试开始,以验证GWT按钮的创建:

@Testpublic void checkText() {
Button b = new Button ();
b. setText (" toto ");
Assert . assertEquals ("toto", b. getText ());
}

如前所述,这样的测试会产生错误:

1 java.lang . ExceptionInInitializerError ...
2 Caused by: java. lang . UnsupportedOperationException : ERROR: GWT. create() is only usable in
3 client code!  It cannot be called, for example, from server code.  If you are running a unit
4 test, check that your test case extends GWTTestCase and that GWT. create() is not called
5 from within an initializer or constructor.
6   at com. google.gwt.core.client.GWT.create (GWT. java : 85 )
7   at com. google.gwt.user.client.ui.UIObject .(UIObject. java : 140 )
8   ... 23 more

为了使Gwt-Test-Utils能够修改GWT类的字节码,必须使用我们专门开发的Java代理执行测试。 因此,我们必须在JVM启动命令中添加一个新参数:-javaagent:path_to_bootstrap.jar。

之后,我们必须在测试代码中安装“ Gwt-Test-Utils”:

1 @Before
2public static void setUpClass() throws Exception {
3   // patch GWT standard components
4   PatchGWT.init();
5 }
6

现在可以验证测试:Gwt-Test-Utils即时替换GWT类的字节码。 这样,将不会启动GWT HostedMode,并且执行时间约为几毫秒。 我们可以使用所有标准工具。

例如,我们可以使用Easymock测试对GWT-RPC服务的调用:

1static interface MyRemoteService extends RemoteService {
2  String myMethod( String param1);
3 }
4
5 static class MyGwtClass {
6  public String myValue;
7
8  public void run() {
9    MyRemoteServiceAsync service = GWT.create(MyRemoteService. class );
10    service.myMethod(" myParamValue ", new AsyncCallbackgt;() {11      public void onFailure( Throwable caught) {myValue = " error ";}12      public void onSuccess( String result) {myValue = result;}13   });14  }15 }16 17 @Mock18 private MyRemoteServiceAsync mockedService;19 20 @Test21 public void checkGwtRpcOk() {22  // Setup 23 24  // mock remote call 25  mockedService.myMethod(EasyMock.eq(" myParamValue "), EasyMock.isA(AsyncCallback. class ));26  expectServiceAndCallbackOnSuccess(" returnValue ");27 28  replay();29 30  // Test 31  MyGwtClass gwtClass = new MyGwtClass();32  gwtClass.myValue = " toto ";33  Assert .assertEquals(" toto ", gwtClass.myValue);34  gwtClass.run();35 36  // Assert 37  verify(); 38  39  Assert .assertEquals("returnValue", gwtClass.myValue);40  }

注意:@Mock注释类似于我们在 Unitils中 可以找到的 注释 它用于声明模拟对象。

2.4此框架的约束和非约束

  • 无需更改/重新开发GWT应用程序的设计即可使其可测试。
  • 您需要通过添加参数-javaagent:path_to_bootstrap.jar来修改这些单元测试的启动命令。 这必须在IDE设置和/或Maven配置(在surefire插件配置中)中完成。
  • 必须使用Java 6 JVM来执行测试(Java 5 JVM不允许您修改本机方法的代码)。 通过更改JRE执行,使用Eclipse很容易。 使用Maven,您只需要更改surefire插件使用的JVM。

这些限制并不是微不足道的,但是我们认为测试框架的优势胜过了它们。

有关Maven配置的完整示例,请参见Gwt-Test-Utils demo1项目 。

2.5结果

在我们的项目中(使用JRockit 1.5编译的26k行GWT应用程序,在Hotspot 1.6下进行了测试),我们完成了600%的单元测试(14k行测试代码),覆盖了85%的代码。 但是,我们将测试集中在GWT应用程序的控制器部分,其目的不是要重新测试GWT,而是要验证我们已实现的行为。

3整合测试

3.1第一限制

Gwt-Test-Utils框架允许我们有效地测试UI。 这些测试的弱点在于它们是单元测试:我们正在测试单个视图的行为。 服务器部分(接收GWT-RPC调用)被模拟。 我们遇到的大多数问题都在视图链接上,视图中有很多GWT-RPC调用。

3.2编写集成测试

在我们的例子中,服务器后端使用Spring。 因此,我们使用SpringJUnit4ClassRunner对其进行测试,它将在JUnit下为我们启动整个服务器后端。 因此,通过添加一些粘合剂,我们“封闭了循环”:我们没有模拟GWT应用程序服务器后端,而是将UI部分连接到服务器后端。

因此,GWT应用程序及其服务器已完全在唯一的JVM中启动并运行,并准备执行测试。 例如,我们可以编写一个测试方案,其中:

  • 启动服务器后端
  • 启动GWT应用程序(只需调用其EntryPoint)
  • 刺激GWT应用程序,它将调用服务器后端
  • 通过意见

这些测试不再是单元测试。 它们是真正的集成测试。

3.3实践

服务器端无需修改。 我们仅添加了一些粘合代码即可将GWT应用程序连接到Spring部件。 我们已经进行了集成测试,可以模拟服务器使用的服务,例如数据库,Webservices等。 我们只是简单地重用了这种环境。

为了模拟GWT应用程序,我们可以编写一些Java。 例如:

1MyView myView = (MyView) RootPanel.get( 0 ) ;
2myView. getButton().click(); 

这不是很实用。 我们需要在各处添加吸气剂。 而且,我们经常会想获取“表X中的第四复选框,它本身位于容器Y中,其自身位于RootPanel中”。 这就是为什么我们开发了一种类似于XPath的小型语言,并提供了一种在给定组件上调用方法的机制。

例如,要到达位于容器第一个小部件中的标签,而标签本身位于RootPanel的第三个小部件中,我们可以编写:

1 /rootPanel/widget(2)/widget(0)

此标签的包含文本,通常可通过getText()方法访问,可通过以下方式访问

1 /rootPanel/widget(2)/widget(0)/text

大量使用Java反射使所有这些成为可能。

可以使用这些XPath在CSV文件中编写测试方案。 这是CSV方案的示例,其中:

  • 启动GWT应用程序
  • 检查标签内容是否包含“ foo”
  • 模拟单击按钮,该按钮通过GWT-RPC调用Spring服务,并替换标签内容
  • 检查标签的内容是否已更改并且现在包含“ bar”

这是方案:

1 initApp;
2 assertExact;foo;/rootPanel/widget(2)/widget(0)/text
3 click;/rootPanel/widget(2)/widget(1)
4 assertExact;bar;/rootPanel/widget(2)/widget(0)/text

少量的代码使我们可以在JUnit中启动此方案。 因此,这些测试的执行方式与单元测试的执行方式相同,只是执行时间更长(由于服务器部分的启动)。

集成测试部分也在Gwt-Test-Utils项目中。 这里提供了文档。

我们可以用Selenium做同样的事情。 有三个主要区别:

  • 由于组件ID,GWT与Selenium不太适合(但是可以做到)。
  • 我们认为,我们的本地化语言更加简单高效。
  • 我们的测试是由JUnit启动的,这意味着我们可以从Eclipse或在Maven构建期间启动它们,这使它们的执行更加容易。

3.4结论

在我们的项目中,我们编写了900个UI单元测试和大约40个集成测试。

这一系列测试确保了我们应用程序所有功能的整体不退缩:

  • 最初的投资并不算大,因为测试系统是在我们构建应用程序时开发的。
  • 好处是巨大的:在大约一年的发展中,我们几乎没有退化。
  • 方案的维护成本很高(每15天几个小时),但是与所产生的收益相比,我们认为这是完全合理的。
  • 完整的应用程序非回归测试套件(在模拟环境中)只需3分钟即可执行。
  • 我们经常在GWT应用程序中进行重构,甚至没有启动GWT:如果非回归测试通过,我们可以确保没有任何问题。

事实证明,GWT是一种UI技术,它通过一些工具使我们能够执行高级测试,从而进一步提高了该技术的生产率。

测试框架及其文档已作为开源项目Gwt-Test-Utils发布 。

翻译自: https://www.infoq.com/articles/gwt_unit_testing/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

gwt 测试

gwt 测试_GWT应用程序的单元和集成测试相关推荐

  1. 【UDS统一诊断服务】四、诊断典型服务(5)— 功能/元件测试功能单元(例行程序功能单元0x31)

    文章目录 四.诊断典型服务(5)- 功能/元件测试功能单元(例行程序功能单元) "功能/元件测试功能单元(例行程序功能单元)"包括的服务: (1)RoutineControl (0 ...

  2. 10个适用于Java程序员的有用单元和集成测试工具

    由于我相信程序员和他们的工具一样好,我总是在空闲时间尝试学习和探索新的工具和库,这个列表是该研究的一部分. 在本文中,我将分享10个最好和必不可少的工具和库,它们可以帮助Java开发人员在各种Java ...

  3. php make test 作用,larablog 系列文章 06 - 测试:使用 PHPUnit 进行单元和功能测试

    到目前为止,larablog 系列文章就要接近尾声了,过去我们已经探讨了开发的核心概念和方式.在继续添加功能之前,是时候介绍测试相关的内容.我们将研究如何通过单元测试和功能测试确保多个组件与功能一起正 ...

  4. 【教程】TestComplete测试桌面应用程序教程(四)

    TestComplete是一款具有人工智能的自动UI测试工具,利用自动化测试工具和人工智能支持的混合对象识别引擎,轻松检测和测试每个桌面,Web和移动应用程序.其中,TestComplete支持测试使 ...

  5. 用VS.NET中的测试工具测试ASP.NET程序

    在编写ASP.NET应用程序的时候,你会花费多长的时间来考虑性能的问题?很不幸,大多数开发者都对性能问题感到很后悔.性能的规划和设计真的需要放在前面和中心位置.你需要考虑自己的目标,并且确保把良好的性 ...

  6. 用Microsoft Application Center Test测试Web应用程序性能

    在看微软的在线讲座时,专家展示了一个软件,Microsoft Application Center Test,能够测试Web应用程序性能,这一直是我想要的软件,没想到在VS.Net企业版里就有,赶紧装 ...

  7. boost::gregorian模块实现测试当天的程序

    boost::gregorian模块实现测试当天的程序 实现功能 C++实现代码 实现功能 boost::gregorian模块实现测试当天的程序 C++实现代码 #include "boo ...

  8. boost::container模块实现虚拟测试分配器的程序

    boost::container模块实现虚拟测试分配器的程序 实现功能 C++实现代码 实现功能 boost::container模块实现虚拟测试分配器的程序 C++实现代码 #ifndef BOOS ...

  9. Boost:测试BOOST_BIND_NO_PLACEHOLDERS的程序

    Boost:测试BOOST_BIND_NO_PLACEHOLDERS的程序 实现功能 C++实现代码 实现功能 测试BOOST_BIND_NO_PLACEHOLDERS的程序 C++实现代码 #def ...

  10. Rails测试《十一》添加邮件发送程序及测试邮件发送程序

    讲到测试邮件发送程序,我们首先要让系统可以发送邮件.我们先来给系统添加发送邮件的功能. Action Mailer in Rails 3是一个不错的视频教程,大家可以参考. 还有就是http://gu ...

最新文章

  1. 前端开发知识总结思维导图
  2. disperse函数 C语言,武汉工业学院电气1006班C语言测试题.doc
  3. 【ICLR2019】Oral 论文汇总
  4. 存放有数组的list排序
  5. html映射共享文件夹,怎么在DOS下映射共享文件夹为本地磁盘
  6. Android 布局
  7. loadrunner—web_url
  8. java面试题--算法集锦(建议收藏)
  9. win10任务栏全透明
  10. C盘满了,要怎么清理才不会误删?
  11. 企业微信应用开发(JS-SDK网页式开发)第一集:创建应用以及配置可信域名
  12. 再读《架构即未来》有感
  13. 单向一对多和双向一对多
  14. 智慧停车(十一) 前期运营策略-停车人,合伙人,授权人
  15. PS 2019 Mac版 自学入门系列(二)——区域选中
  16. 游程编码(运行长度编码)
  17. 计算机合成图像的技术可应用于,计算机系统概论第五章测验与答案.doc
  18. TP-LINK路由器任意代码执行漏洞CVE-2017-9466 WR841N V8版本受影响
  19. UE4人物移动时的摄像机抖动
  20. uniapp 微信小程序 editor富文本编辑器 api 使用记录

热门文章

  1. 计算机网络:广域网的基本概念
  2. Error: Duplicate resources
  3. Duplicate问题
  4. 计算机无法打开隐藏文件,处理怎么打开隐藏文件
  5. 自己写jquery表单验证
  6. Sql Server 2008服务启动失败,错误17058
  7. 【Selenium IDE】下载安装Chrome和Firefox插件IDE
  8. WhatsApp创始人:从领救济到身价68亿
  9. android 9.0user版本如何开启root,打开su
  10. win10怎么一键释放运行内存