如您所见,清单 6 的响应代码为 200 —— 表示 OK 的 HTTP 响应代码(参见 参考资料 了解关于 HTTP 响应代码的更多信息)。为简便起见,调用失败时仅返回错误消息。但使用现成的扩展结构,您可以多次重新尝试调用或将故障转移到另一个 URL 缩短服务,从而使这个方法更健壮。 在 test/integration/org/grails/shortenurl 目录中创建对应的 IsGdTests.groovy
文件,如清单 7 所示。输入 IsGd 类
传递 curl 查看失败
Web 服务类的细节
现在这个插件的核心功能已经实现并经过测试,您应该创建一个方便的服务,以一种 Grails 友好的方式公开这两个实用程序类。 创建
|
import org.grails.shortenurl.* class ShortenUrlService { boolean transactional = false def tinyurl(String longUrl) { return TinyUrl.shorten(longUrl) } def isgd(String longUrl) { def shortUrl = IsGd.shorten(longUrl) if(shortUrl.contains("error")){ log.error(shortUrl) } return shortUrl } } |
与前面的集成测试相似,确保将 transactional
标记设置为 false
。这些调用不涉及任何数据库,所以不必将它们封装到一个事务中。
注意,isgd()
方法将记录任何企图缩短一个无效 URL 的日志。所有 Grails
工件将在运行时使用一个 log
对象注入。可以调用 log
对象上与想要的日志级别相对应的方法,这些日志级别包括: debug
、info
和 error
等(参见 参考资料
了解关于日志记录的更多信息)。您稍后将会看到,编写单元测试时,处理这个注入的 log
对象需要一个额外步骤。
当 Grails 为您创建服务时,它将把相应的测试添加到 test/unit 目录。通常,您需要将 ShortenUrlServiceTests.groovy 移动到 test/integration 目录,因为在语义上,它是一个集成测试,而不是一个单元测试 — 依赖外部资源测试服务。但现在,您应将它保留在 test/unit 目录中,以便我能够向您展示几个单元测试技巧。将清单 10 中的代码添加到 ShortenUrlServiceTests.groovy。
清单 10. 测试ShortenUrl
服务 import grails.test.* class ShortenUrlServiceTests extends GrailsUnitTestCase { def transactional = false def shortenUrlService protected void setUp() { super.setUp() shortenUrlService = new ShortenUrlService() } protected void tearDown() { super.tearDown() } void testTinyUrl() { def shortUrl = shortenUrlService.tinyurl("http://grails.org") assertEquals "http://tinyurl.com/3xfpkv", shortUrl } void testIsGd() { def shortUrl = shortenUrlService.isgd("http://grails.org") assertEquals "http://is.gd/2oCZR", shortUrl } void testIsGdWithBadUrl() { def shortUrl = shortenUrlService.isgd("IAmNotAValidUrl") assertTrue shortUrl.startsWith("An error occurred:") } } |
注意,将 transactional
标志设置为 false
后,我们声明了 shortenUrlService
变量。然后在 setUp()
方法中初始化服务。为每个服务调用 setUp()
和 tearDown()
方法。
如果这是一个集成测试,则不会出现错误。但由于这是一个单元测试,testIsGdWithBadUrl()
方法失败并显示错误消息:No such property: log for class: ShortenUrlService
。在
Web 浏览器中打开 test/reports/html/index.html,您将看到如图 2 所示的错误消息。
如上所示,log
对象并没有注入服务中以进行单元测试。(记住:单元测试意味着完全隔离运行)。好在解决这个问题只需在
setUp()
方法中添加一行 — mockLogging(ShortenUrlService)
— 如清单 11 所示。
log
对象 protected void setUp() { super.setUp() mockLogging(ShortenUrlService) shortenUrlService = new ShortenUrlService() } |
mockLogging()
方法将一个模拟 log
对象注入到服务中。这个模拟记录器将它的输出发送到 System.out
而不是任何已定义的
log4j 输出器。要查看输出(如图 3 所示),再次输入 grails test-app
,单击
ShortenUrlServiceTests
的 HTML 报告页面底部的
System.out 链接。
您还可以为这个插件集成大量其他 Grails 工件 — 一个自定义 TagLib 以缩短 GSP 中的 URL,一个自定义编解码器 — 但现在您已经充分了解一个插件可以提供的内容,在这里就不一一演示了。在下一个小节中,我们将把这个插件原样打包并集成到另一个 Grails 项目中。
要准备一个完整的 Grails 应用程序以便部署,通常需要输入 grails war
。但对于插件,则应输入
grails package-plugin
。这样,您的项目中将生成一个 grails-shortenurl-0.1.zip
文件。
回想一下,“精通 Grails:了解插件” 介绍过,所有 Grails 插件都作为 ZIP 文件分发。查看一下 home 目录中的 .grails/1.1.1/plugins 目录,您将看到类似的插件名称,比如 grails-hibernate-1.1.1.zip 和 grails-searchable-0.5.5.zip。
假如 ShortenUrl 是一个公共插件,您可以输入 grails release-plugin
将您的更改提交到 Grails Plugins 门户网站。然后,任何人都可以输入 grails
install-plugin shortenurl
将它集成到他们的项目中。您也可以在本地轻松安装私有插件,只需提供
ZIP 文件在您的本地文件系统上的完整路径。
要测试这一点,在 shortenurl 目录外创建一个新的空目录。输入 grails create-app
foo
创建一个简单的应用程序。切换到 foo 目录并输入 grails install-plugin
/local/path/to/grails-shortenurl-0.1.zip
,当然,要用实际插件路径替换其中的路径。您将看到类似于清单
12 的输出:
$ grails install-plugin /code/grails-shortenurl-0.1.zip Welcome to Grails 1.1.1 - http://grails.org/ Licensed under Apache Standard License 2.0 Grails home is set to: /opt/grails Base Directory: /code/foo Running script /opt/grails/scripts/InstallPlugin.groovy Environment set to development [copy] Copying 1 file to /Users/sdavis/.grails/1.1.1/plugins Installing plug-in shortenurl-0.1 [mkdir] Created dir: /Users/sdavis/.grails/1.1.1/projects/foo/plugins/shortenurl-0.1 [unzip] Expanding: /Users/sdavis/.grails/1.1.1/plugins/grails-shortenurl-0.1.zip into /Users/sdavis/.grails/1.1.1/projects/foo/plugins/shortenurl-0.1 Executing shortenurl-0.1 plugin post-install script ... Plugin shortenurl-0.1 installed |
如您所见,本地、私有插件的生命周期和公共插件的相同。
在文本编辑器中打开 foo/application.properties 文件,确认 plugins.shortenurl 如清单 13 所示。
清单 13. 确认插件出现在 application.properties 中 #utf-8 #Wed Aug 19 14:38:24 MDT 2009 app.version=0.1 app.servlet.version=2.4 app.grails.version=1.1.1 plugins.hibernate=1.1.1 plugins.shortenurl=0.1 app.name=foo |
安装插件后,应该确认它能够正常工作。输入 grails create-controller
test
。打开 grails-app/controllers/TestController.groovy
并添加清单 14 中的代码。
class TestController { def shortenUrlService def index = { render "This is a test for the ShortenUrl plug-in " + "Type test/tinyurl?q=http://grails.org to try it out." } def tinyurl = { render shortenUrlService.tinyurl(params.q) } } |
注意,def shortenUrlService
将服务注入到控制器中。输入
grails run-app
启动应用程序。在 Web 浏览器中访问 http://localhost:9090/foo/test/tinyurl?q=http://grails.org,应该可以看到如图
4 所示的结果。
如果您访问 http://tinyurl.com/3xfpkv,肯定会进入 grails.org 页面。
如您所见,创建 Grails 插件与创建典型的 Grails 应用程序没有多大区别。创建插件时,应该输入
grails create-plugin
而不是 grails
create-app
,应该输入 grails package-plugin
而不是 grails war
。除了在 GrailsPlugin.groovy
描述符文件中添加的细节不同外,所有中间步骤(创建服务和编写测试等)都是相同的。
本文通过 mockLogging()
方法简单探索了 Grails 单元测试的模拟功能。在下一篇文章中,我将展示其他几种极其有用的模拟方法:
mockDomain()
和 mockForConstraintsTests()
等。在此之前,请尽情享受
Grails 的带来乐趣吧!
描述 | 名字 | 大小 | 下载方法 |
---|---|---|---|
源代码 | j-grails09159.tar |
820KB |
火龙果软件/UML软件工程组织致力于提高您的软件工程实践能力,我们不断地吸取业界的宝贵经验,向您提供经过数百家企业验证的有效的工程技术实践经验,同时关注最新的理论进展,帮助您“领跑您所在行业的软件世界”。 |
资源网站: UML软件工程组织 |