我们经常遇到模板错误的问题,偶尔会潜入我们的生产站点。如果有提前解决这些问题的工具或解决这些问题的策略,则可以将其添加到交付管道中。
根据我的经验,在尝试渲染模板(忽略配置)时,Freemarker实际上只有两类错误:
尽管整理工具通常确实会发现代码中的错误,但整理工具并不能代替基本测试的需求,这对您在这里遇到的情况来说是更好的解决方案,因为您会在生产代码中看到异常。
无论好坏,Freemarker关于谁在使用数据以及谁在使用标记的假设都是具有不同技能的不同人。假设是这种情况(并且您有足够的Java工程资源可供使用),从测试过程的角度来看,您有两种方法来解决此问题(尽管确实很严格,但两者都需要)。
在我上一份工作中,我们独自使用了这种方法。基本上,前端工程师会在特殊的Web前端上破解模板,其中编辑后的模板直接位于包含两个清单的配置路径上:
'版本'本质上是两层硬编码的Java对象,其中第1层在所有模板中都是一致的,而第2层是特定于模板的变体。由于我们的大多数电子邮件都是帐户级别的通知,因此,仅拥有全局数据模型就可以节省大量的时间和重复使用的费用,因此我们很少需要研究一些小问题。
好处
不太好
另一个选择是在创建每个模板时进行表单单元测试。因为Freemarker中的异常都是在编译时发生的,所以您只需要执行以下操作(在完成初始设置之后):
Template temp = cfg.getTemplate("myTestedTemplate.ftl");
temp.process(myTestDataModel, myIgnoredOutput); // No exceptions -> OK for us
请注意,在这种情况下,您不必关心结果,只需要编译即可。这很重要,因为您很容易陷入Java调试编译输出的困境,而无法解决当前问题。和以前一样,您也很可能希望在此处进行相同的两层单元测试:
好处
不太好
[如果您有时间做这两种情况,我建议您使用单元测试来处理边缘情况和其他问题,这些问题在弹出时会发现,然后是Web前端进行开发,因此不需要开发页面重新编译。能够对前端进行版本控制是非常有益的,但是目标是首先防止生产过程中的错误到构建过程中。启动,然后全部优化。
如果您是指运行时输出错误而不是模板语法错误,则可以使用一组(易碎的)“期望得到”集成测试。这是否合适取决于模板的复杂性和动态性。如果您只想进行一些简单的“烟熏”测试,这可能是一个很好的解决方案。
对于每个模板,至少创建一个测试。使用具体/静态/预先指定的输入数据和具体/静态/预先指定的输出结果。更改后,第一次必须手动生成并验证此输出,但此后可以保存并编写脚本。如果模板提取无法设置为固定输入的自身数据(例如日期等),请屏蔽此数据或将其从预期输出中删除。每个自动测试应:
精确的输出相等性是最容易实现并确保正确的输出。如果需要,每个模板有多个测试。我不会尝试变得聪明,只要让计算机完成无聊的重复性工作即可。我会忽略模板中需要在第一次通过时掩盖的部分(有些测试总比没有好。当您以后决定为他们编写显式测试时,为您编写显式测试可以提高可靠性,足以值得您付出努力(或过去做错的任何事情。)
此解决方案具有以下警告。
范围太大。模板或数据模型中任何内容的任何更改都可能需要更新测试。使用“ diff”可能有助于手动验证并确定在数据模型和/或模板更改时如何修改测试。
代码拒绝和模块化会导致测试问题。使用良好的模块化代码,一次代码更改会影响所有模板中的数据,但是静态测试需要在发生这种情况时独立更改和重新验证所有测试。解决此问题的工作量不大,因此代码越好,模块化程度越高,这会导致更多的工作:(
复杂的模板很难测试。仅使用几套静态数据来获得良好的模板覆盖率可能会有问题。这可能意味着模板正在执行过多的“处理”,而实际上并没有被用作模板。无论如何,这可能不是一个好主意。
我不知道为您提供帮助的工具,但是要抓住语法错误,您要做的就是将所有模板文件都分配给new Template("whatever", theTemplateFileReader);
。不幸的是,您无法以这种方式检测运行时错误,例如对不存在的变量/宏/导入的引用。为此,您可以调用Template.process
,但是如果没有在实际应用程序中拥有的数据模型,那当然就没有意义了。