JSF อัพเดต bean ที่ได้รับการจัดการด้วย Listener ServletContext สำหรับการทดสอบ

ในแอปพลิเคชัน JSF 2.2 ฉันต้องการสร้างไฟล์ war สำหรับการทดสอบกับ 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 และ Listener เพื่อแทนที่ออบเจ็กต์ไม่ได้ผล โค้ดมักจะใช้โค้ดที่จัดการโค้ดการผลิตที่ไม่ได้จำลองเสมอ

การกำหนด @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 build:

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