JSF使用ServletContext监听器更新托管bean以进行测试

时间:2017-05-12 21:16:05

标签: jsf mocking

在JSF 2.2应用程序中,我想构建一个war文件,用于使用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的可靠方法,还是我很幸运?

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

1 个答案:

答案 0 :(得分:0)

同时使用@ManagedBean注释和侦听器替换对象不起作用。代码总是使用unmocked生产代码托管bean。

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

我最终得到了这个:

  • 在真实bean及其模拟器上放置@ManagedBean注释名称相同。

  • 构建时,只在构建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;
    }
}

这解决了我的问题。希望别人觉得它很有用。