Обновление управляемого компонента JSF с прослушивателем ServletContext для тестирования

В приложении JSF 2.2 я хочу создать военный файл для тестирования с помощью Selenium. В этом webtest.war я хочу заменить центральный класс, называемый NodeCache, фиктивной версией, называемой WebtestNodeCache, чтобы исключить базу данных и другие внешние зависимости из тестов.

NodeCache — это управляемый компонент:

@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-компонент в контексте приложения или мне просто повезло?

Есть ли лучший способ проникнуть в тестовые манекены?


person Robert    schedule 12.05.2017    source источник


Ответы (1)


Использование аннотации @ManagedBean и прослушивателя для замены объекта не сработало. В коде всегда использовался управляемый bean-компонент без макета производственного кода.

Определение нового @ManagedBean с тем же именем является ошибкой и препятствует развертыванию.

Я закончил с этим:

  • Поместите аннотацию @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;
    }
}

Это решает проблему для меня. Надеюсь, что кто-то еще найдет это полезным.

person Robert    schedule 12.06.2017