首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Dojo 敏捷开发:集成 DOH 单元测试到 Ant build (3)

Dojo 敏捷开发:集成 DOH 单元测试到 Ant build (3)

集成浏览器运行方式命令行运行方式在很多方面存在着缺陷,例如:无法测试与 DOM 操作相关的代码,无法测试浏览器的兼容性等等。而浏览器运行方式就能够弥补这些缺陷。可是将浏览器运行方式集成到 Ant build 中会相对复杂一些。这种方式需要一个可访问服务器的支持,这个服务器可以是一个部署好的公用服务器,也可以是在 build 中启动的一个本地服务器,下面以本地服务器为例。在 build 中启动一个本地的 Web 服务器可以使用嵌入式的 Web 服务器,例如 Jetty。
在浏览器运行方式中,主入口是一个 html 文件,例如 runner.html。我们可以将该文件放在 WebContent 的根目录中,并将启动的 Web 服务器的 Web 应用根目录设置为 WebContent,这样就可以通过 http://localhost/runner.html 访问。
所以在 Ant build 中启动单元测试就变得简单了,只需要启动一个浏览器并且访问该地址即可,这里的浏览器可以是任何想要测试的浏览器,也可以将每种浏览器测试一遍。以 Firefox 为例,Ant 片段如清单 5 所示。
清单 5. Ant 中启动浏览器
1
2
3
4
5
<target name="runUT">
   <exec executable=" C:\Program Files\Mozilla Firefox\firefox.exe">
       <arg value="http://localhost/runner.html"/>
</exec>
</target>




其中,executable 是浏览器应用程序可执行文件或命令的路径,arg 是访问 runner.html 的 web 路径。这条命令可以达到启动单元测试的目的,但是当浏览器被启动起来以后这条命令就直接返回了,所以 Ant build 可能在单元测试执行结束之前就已经返回了,无法得到单元测试的执行结果。所以我们需要一个办法让 Ant build 等待单元测试执行结束。这时候可以借助 Web 服务器来传递这个消息。
我们可以实现一个服务器端的消息转接服务,该服务可以通过 HTTP 写入或者读取单元测试的执行结果。在 runner.html 中添加一段 JavaScript 代码用于在单元测试执行结束后将结果通过 Ajax 方式写入到服务中。除此之外,我们还需要实现一个 Java 可执行类,该类以一定间隔从服务器端的服务中去取执行结果,当无法取得执行结果时等待一定间隔重试,直到取得执行结果,然后输出执行结果并且根据执行结果是否成功决定返回结果。在 Ant build 中,当单元测试被启动后启动该 Java 可执行类。通过这个方式我们可以让 Ant build 等待单元测试执行结束并且将单元测试的结果输出,当单元测试失败时让 build 失败。
  •                                          编写消息转接服务                          消息转接服务是一个简单的服务器端处理单元,以什么方式实现取决于项目的服务器端技术,可以是 Servlet、REST executor 等等。下面以 REST executor 为例实现该处理单元。
    我们需要将写入和读取的 HTTP 请求都定向到这个处理单元中。写入的 HTTP 请求附带 HTTP 消息体,读取的 HTTP 请求没有 HTTP 消息体。所以该处理单元可以通过是否有 HTTP 消息体来判断是写入请求还是读取请求。实现代码如清单 6。
    清单 6. 消息转接服务代码示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class ResultService extends ReqExecutor {

               private String result = "";
               public ReqExecutor newInstance() {
                    return this ;
           }
                public HTTPResponse execute(HTTPRequest req) {
                    String body = req.getBody();
                    if(body != null && !body.trim().equals("")) result = body;
                    else {
                       return new StringResponse(result);
                    }
                }
    }




    为了保证写入和读取的 HTTP 请求都由同一个 ResultService 对象进行处理,所以这里当 newInstance 时就返回 this。
    将该消息注册到 REST framework 中,并为其指定一个不与其它服务冲突的 URL,例如: ”/resultService”。
  •                                          修改 DOH 的执行代码                         在 DOH 中,runner.js 中有一个 doh._report 方法负责在单元测试执行结束后汇报执行结果。我们可以修改该方法,让它在所有测试执行结束后把运行结果通过 Ajax 方式发送给服务器端的消息转接服务。修改后的方法体如清单 7。
    清单 7. 修改后的 doh._report 方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    doh._report = function (){
            this .debug("| TEST SUMMARY:");
            this .debug(this ._line);
            this .debug("\t", this ._testCount, "tests in",
                                 this ._groupCount, "groups");
            this .debug("\t", this ._errorCount, "errors");
            this .debug("\t", this ._failureCount, "failures");
      //---------------------------------------------------------------------------
                 // 定义 request 对象,把需要写入 build 的信息传递给 server 端
                 var request = {
                     //url 为用于接收参数的 rest excutor
            url: "http://localhost/resultService",
            handleAs: "text",
            preventCache: true ,
            content :
            // 总 test case 数量
            "testCount: " + this ._testCount + "\n" +
            // 总 test suit 数量
            "groupCount: " + this ._groupCount + "\n" +
            // 出错数量
            "errorCount: " + this ._errorCount + "\n" +
            // 失败数量
            "failureCount: " + this ._failureCount + "\n" +
            // 全部执行过程中的 log 内容
            "logBody: " + dojo.byId("logBody").innerHTML +
                     // 执行结果是成功或者失败,将被 Ant build 用于决定是否让 build 失败
            this ._errorCount + this ._failureCount > 0 ? "successful"  : "failed",
            load: function (data, ioargs){
                console.log("ok");
            },
            error: function (error){
                console.log("error");
            }
                   };
                   // 向 server 端发送 POST 请求
                   dojo.xhrPost(request);
    }




    方法体中分割线以上部分为原方法体,以下部分为增加的代码。在该方法中可以分别通过内部变量或者 innerHTML 获得所有已执行单元测试的统计信息(比如:test case 的数量、test suit 的数量)和执行结果(比如:出错数量、失败数量、执行的 log 内容)。在以上的样例实现中,只是简单的将所有这些内容以纯文字的形式返回给消息转接服务。如果不希望这样,当然也可以选择其它的方式(例如 JSON)和内容,但是这样也同时需要修改消息转接服务和 Ant build 中的 Java 可执行类。
  •                                          集成 Java 可执行类到 Ant build                          这个 Java 可执行类需要提交 HTTP 请求到 http://localhost/resultService,并且获取消息转接服务所保存的执行结果。代码如清单 8。
    清单 8. Java 可执行类示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
                    import java.io.IOException;
    import java.io.InputStream;
    import java.net.URL;

    public class ResultRequest {

      public static void main(String[] args) throws IOException {
           URL u = new URL("http://localhost/resultService");
           //int tryCounts = 0;
           while (true ){
               //if(tryCounts > 60) System.exit(1);
               //tryCounts++;
               InputStream inStream = u.openStream();
               String result = readContentFromStream(inStream);
               if (result != null && !result.trim().equals("")) {
                   System.out.println(result);
                   if (result.endsWith("failed")) System.exit(1);
                  else return ;
               } else {
                   Thread.sleep(1000);
               }
           }
       }
    }




    该类打开连接消息转接服务的 URL,获得 URL 所返回的内容,如果返回的内容为空则继续等待,等待时间可以设置为一个合适的时间,比如 1 秒钟;如果返回的内容不为空则说明已经取到单元测试的运行结果,然后输出取到的结果并且从结果中获得单元测试是否成功,如果不成功则以错误代码返回,否则直接返回。
    将该类集成到 Ant build 中,首先将该类编译打包,然后放在一个 build 脚本可以访问的库目录中,例如 WebContent/lib。Ant 片段如清单 9。
    清单 9. 集成 Java 可执行类到 Ant
    1
    2
    3
    <target name="testResult" depends="runUT">
       <java classname="ResultRequest" classpath="lib" failonerror=”true”/>
    </target>




    该 target 在 runUT target 后执行,所包含的工作就是执行这个 Java 类。
返回列表