Hatena::ブログ(Diary)

tomoTakaの日記

2013-01-05

JavaFXを使ってWeb画面のテスト

以前にseleniumで簡単な画面のテストを実装してみたので、同じことを@skrbさんの記事 JavaFX + JUnit で JavaScript のユニットテストをする その 2 - JavaFX in the Boxを参考にJavaFXで挑戦しました。
なかなか思ったように実装できなくて困っています、、、

  • ★1以下の2パターンのテストを続けて実行したかったのですが、2回目の「Hello」画面をJavaFXで再度loadするところが思ったように動作しないのです。

1回目Hello Testで「Hello」画面 ->「Greeting」画面でh1に「Hello JavaFX」が設定されることをテスト
2回目おはようTestで「Hello」画面 ->「Greeting」画面でh1に「おはよう JavaFX」が設定されることをテスト

  • ★2Web画面の操作をjavascriptで実装したのですが、もっと簡潔にわかりやすく実装したいのです。
  • ★3JavaFX側で実装が誤っているとJUnit側のテストが待ち状態のままで終わらなくなってしまいます。

  • テストクラス
public class HelloTest {
    private static DummyApp dummyApp;
    private static ExecutorService service;
    
    public HelloTest() {
    }
    
    @BeforeClass
    public static void setUpClass() throws InterruptedException {
        service = Executors.newFixedThreadPool(1);
        service.submit(new Runnable() {
            @Override
            public void run() {
                Application.launch(test.DummyApp.class);
            }
        });
        dummyApp = DummyApp.getInstance();
    }
    
    @AfterClass
    public static void tearDownClass() {
        dummyApp.shutDown();
    }
    
     @Test
     public void hello() throws InterruptedException {
        Map<String, String> results = dummyApp.HelloTest("JavaFX", "0", "0");
        String result = results.get("h1");
        assertThat(result, is("Hello JavaFX"));        // このテストはグリーンに
     }

     @Test
     public void おはよう() throws InterruptedException {
        Map<String, String> results = dummyApp.HelloTest("JavaFX", "1", "1");
        String result = results.get("h1");
        assertThat(result, is("おはよう JavaFX"));        // ここでJavaFX側の★1のengine.loadが動作しないような・・・
     }
}

  • JavaFX側(Web画面を操作)
public class DummyApp extends Application {
    private static WebEngine engine;
    private static DummyApp app;
    private static BlockingQueue<DummyApp> instance = new LinkedBlockingDeque<>();
    private BlockingQueue<Map<String, String>> arguments = new LinkedBlockingDeque<>();
    private BlockingQueue<Map<String, String>> results = new LinkedBlockingDeque<>();
    
    @Override
    public void start(Stage primaryStage) {
        app = this;
        engine = new WebEngine();
        addListner();
        engine.load("http://localhost:8080/HelloSample/faces/Hello.xhtml");
    }
    
    public static DummyApp getInstance() throws InterruptedException {
        return instance.take();
    }
    
    public void shutDown() {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                Platform.exit();
            }
        });
    }
    
    public Map<String, String> HelloTest(
            String name, String greetSel, String lang) throws InterruptedException {
        Map<String, String> params = new HashMap<>();
        params.put("name", name);
        params.put("greetSel", greetSel);
        params.put("language", lang);
        arguments.put(params);
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                try {
                    if (!engine.getTitle().equalsIgnoreCase("Hello")) {
                        engine.load("http://localhost:8080/HelloSample/faces/Hello.xhtml");  // ★1ここで「おはよう」Test時に最初の画面をloadしたいのですが、、、
                        instance.take();
                    }
                    Map<String, String> params = arguments.take();
                    String nameVal = params.get("name");
                    String selVal = params.get("greetSel");
                    String langVal = params.get("language");
                    engine.executeScript("document.getElementById('form1:name').value = '" + nameVal + "'");    // ★2この辺の処理ももっと簡潔に書ける方法がないのかな?
                    engine.executeScript("document.getElementsByName('form1:greetSel')[" + selVal + "].checked = true");
                    engine.executeScript("document.getElementById('form1:language').options[" + langVal + "].selected = true");
                    engine.executeScript("var btn = document.getElementById('form1:greet'); btn.click();");
                } catch (InterruptedException ex) {
                    Logger.getLogger(DummyApp.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
        return results.take();
    }

    private void addListner() {
        engine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
            @Override
            public void changed(ObservableValue<? extends State> ov, State oldState, State newState) {
                if (newState == State.SUCCEEDED && engine.getTitle().equalsIgnoreCase("Hello")) {
                    try {
                        instance.put(app);
                    } catch (InterruptedException ex) {}
                }
                if (newState == State.SUCCEEDED && engine.getTitle().equalsIgnoreCase("Greeting")) {
                    Document doc = engine.getDocument();
                    NodeList nodes = doc.getElementsByTagName("H1");
                    Node h1Node = nodes.item(0);  // ★3例えばここで「nodes.item(1)」と間違って実装するとJUnitのTestが待ち状態になってしまいます
                    Map<String, String> result = new HashMap<>();
                    result.put("h1", h1Node.getTextContent());
                    try {
                        results.put(result);
                    } catch (InterruptedException ex) {}
                }
            }
        });
    }           
}

実装はtomoTaka01/HelloSampleTest ? GitHubにアップしました。
何かいい解決策があればコメントお願いします。>-<

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/tomoTaka/20130105/1357394523