JSF 更新管理的 bean 与 ServletContext 侦听器进行测试



在JSF 2.2应用程序中,我想构建一个战争文件来测试Selenium。在webtest.war中,我想用一个名为WebtestNodeCache的模拟版本替换一个名为NodeCache的中心类,以将数据库和其他外部依赖项排除在测试之外。

NodeCache 是一个托管 Bean:

@javax.faces.bean.ManagedBean(name = NodeCache.INSTANCE)
@javax.faces.bean.ApplicationScoped
public class NodeCache {
public static final String INSTANE = "nodecache";
// ...
}

为了潜入WebtestNodeCache,我使用像这样的ServletContextListener:

public class WebtestContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent event) {
WebtestNodeCache nodeCache = new WebtestNodeCache();
ServletContext context = event.getServletContext();
context.setAttribute(NodeCache.INSTANCE, nodeCache);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {}
}

在普通构建中,WebtestContextListener 和 WebtestNodeCache 被排除在 war 文件中,在测试构建中,它们被包括在内。

这似乎有效:当我登录时,我从WebtestNodeCache中获取虚拟节点。

这是在应用程序上下文中替换 bean 的可靠方法,还是我只是很幸运?

有没有更好的方法来潜入测试假人?

同时使用@ManagedBean注释和侦听器来替换对象不起作用。代码始终使用未模拟的生产代码托管 bean。

定义具有相同名称的新@ManagedBean是一个错误,会阻止部署。

我最终得到了这个:

  • 将具有相同名称的@ManagedBean注释放在真正的 bean 及其模拟上。

  • 构建时,只在构建 webtest.war 时包含模拟,而不包括在常规构建中。

  • 构建
  • 时,让构建脚本(在我的例子中为 Gradle)复制和过滤源代码,在生产代码中查找@ManagedBean声明背后的特殊注释,并删除这些行以删除生产代码上的@ManagedBean声明,以便只保留模拟中的声明。

所以原来的NodeCache现在看起来像这样:

@javax.faces.bean.ManagedBean(name = NodeCache.INSTANCE) // webtest:remove
@javax.faces.bean.ApplicationScoped // webtest:remove
public class NodeCache {
public static final String INSTANE = "nodecache";
// ...
}

并且模拟版本具有相同的注释,只是没有注释:

@javax.faces.bean.ManagedBean(name = NodeCache.INSTANCE)
@javax.faces.bean.ApplicationScoped
public class WebtestNodeCache extends NodeCache {
// ...
}

以下是 Gradle 构建脚本的相关部分:

boolean isWebtest = false
gradle.taskGraph.whenReady { taskGraph ->
isWebtest = taskGraph.hasTask(compileWebtestWarJava);
}
task copySrc(type: Copy) {
from "src"
into "${buildDir}/src"
outputs.upToDateWhen {
// Always execute this task so that resources do or don't get filtered
// when switching between normal war file and webtests.
false
}
filter { String line ->
isWebtest && line.contains("webtest:remove") ? null : line;
}
}

这为我解决了问题。希望其他人觉得有用。

最新更新