4

これを説明する方法がわかりません。しかし、試してみます.. swingx の JXTreeTable を操作している間、Fest のクロールが遅くなります。最初は遅くなりません。しばらくは正常に動作しますが、しばらくすると同じ操作を繰り返すと速度が大幅に低下します。

これについては、github でバグを報告しました。これが私が間違っていることであるかどうか教えてください。SSCCE を作成しようとしたときに、問題を再現できません。

とにかく、これが減速のビデオです。

http://screencast.com/t/liNttCw2In0w

0.39 秒から 0.40 秒の間に一連の操作が実行されます。これらは、JXTreeTable に 1 つの行がある場合に行われます。

時間 0.49 から記録の終了まで同じ操作が繰り返されますが、テーブルには 3 つの行があり、マウスをクリックするのに非常に時間がかかります。

フェストが遅くなったときに撮ったスクリーンショットを添付して、それをもっと説明しようとしました

ここに画像の説明を入力

これは、作業を行うコードです。

ステップ 1) ツリーからノードを選択するには、次のようにします。

JTreeFixture folioTreeFixture = importShareholders.panel("treePanel").tree("folioTree");

        folioTreeFixture.separator("~");
        folioTreeFixture.selectPath(new StringWrapper("Shareholders", true)+"~"+
             (ShareType.isEquity(shareType) ? new StringWrapper("Equity Folios", true) : new StringWrapper("Preference Folios", true))+"~"+
                new FolioTreeRep(folio.getName(),folioNo, shareType).toString());

ステップ 2) JXTreeTable から行を検索して選択する

int selectRow=-1;
JTableFixture table=importShareholders.table("historyTable");
for(int i=0;i<table.rowCount();i++){
    String certificateNumber = table.cell(TableCell.row(i).column(ShareholderHistoryTable.columnIndex(ShareholderHistoryTable.CERT_NO))).value();
    String remarks=table.cell(TableCell.row(i).column(ShareholderHistoryTable.columnIndex(ShareholderHistoryTable.REMARKS))).value();
    if(StringUtils.isEmpty(remarks) && StringUtils.isNotEmpty(certificateNumber) && Integer.parseInt(certificateNumber)==certNo){
        selectRow=i;
        break;
    }
}
if(selectRow==-1){
    fail("Couldn't find certificate number to transfer");
}

手順 3) ポップアップ メニューを表示し、行をクリックする

table.showPopupMenuAt(TableCell.row(selectRow).column(0)).menuItem("btnTransfer").click();

なぜ減速するのかわかりません。他にご不明な点がございましたら、お気軽にお問い合わせください。問題を解決するための助けに感謝します

アプリケーションのプロファイルを作成しましたが、不都合なことが起こっていることはわかりません。アプリケーションのプロファイリングの経験はあまりありません。誰かがこれをもう一度見てくれたら幸いです。あなたのキットでプロファイリングし、スナップショット ダンプをここにアップロードしました。

https://www.dropbox.com/s/dh976v01q9c3sgj/ImportShareholderData.shouldTransferAndSplit-2013-06-14-shutdown.snapshot.zip

どんな助けでも大歓迎です..

編集:

手動で行うと同じことが機能することを忘れていたと思います。フェストで遅くなるだけです。それはおそらくフェストに問題があると私に信じさせますか?

申し訳ありません。

EDIT 2: Marcin のリクエストに応じて (Marcin の遅延について申し訳ありません).最初の行が分割されているときのコードは次のとおりです。

public List<Integer> splitRowEqually(ShareType shareType, String date, int folioNo, int certNo, int... certnos) throws NoSuchFieldException,     TorqueException {
    //select a tree node
    selectFolioInTree(shareType, folioNo);
    Pause.pause(new Condition("Wait until tab is created") {
        @Override
        public boolean test() {
            return importShareholders.tabbedPane().tabTitles().length>0;
        }
    });
    //select a row on the table to split
    int row=selectRowWithCertNunber(certNo);
    List<Integer> rowsIndexes=new ArrayList<Integer>();
    JTableFixture table = importShareholders.table();
    //show popup menu on that row and select split
    table.showPopupMenuAt(row(row).column(columnIndex(TRANS_TYPE))).menuItem("btnSplit").click();
    DialogFixture splitDialog=FinderUtilities.getDialogWithTitle("Split Share Certificate");
    splitDialog.textBox("tfDateOfSplit").setText(date);
    int noOfShares= Integer.parseInt(table.cell(row(row).column(columnIndex(NO_OF_SHARES))).value());
    int distFrom= Integer.parseInt(table.cell(row(row).column(columnIndex(DIST_NO_FROM))).value());
    int distTo= Integer.parseInt(table.cell(row(row).column(columnIndex(DIST_NO_TO))).value());
    //split the row into the number of times decided by the certnos array
    int noOfSharesInEachSplit=noOfShares/certnos.length;
    for(int i=0;i<certnos.length;i++){
        int distToInSplit = distFrom + noOfSharesInEachSplit-1;
        enterSplitRowDetails(splitDialog, certnos[i], distFrom, distToInSplit<=distTo ? distToInSplit : distTo);
        distFrom=distToInSplit+1;
        rowsIndexes.add(row++);
    }
    splitDialog.button("btnSplit").click();
    return rowsIndexes;
}

//selects a node from the left hand side tree
public void selectFolioInTree(final ShareType shareType,final int folioNo) throws TorqueException {
    JTreeFixture folioTreeFixture = importShareholders.panel("treePanel").tree("folioTree");
    folioTreeFixture.separator("~");
    // I use these wrapper classes - StringWrapper and FolioTreeRep, so that I can get a html 
    // string for the tree node like <html><b>Shareholder</b></html>
    String treePath = new StringWrapper("Shareholders", true) + "~" +
            (ShareType.isEquity(shareType) ? new StringWrapper("Equity Folios", true) : new StringWrapper("Preference Folios", true)) + "~" +
            new FolioTreeRep(mapOfFolioNames.get(folioNo), folioNo, shareType).toString();
    folioTreeFixture.clickPath(treePath);
}

//search the table for a row that contains the cert no provided in the Certificate Number column.
private int selectRowWithCertNunber(int certNo) throws NoSuchFieldException {
    int selectRow=-1;
    JTableFixture table=importShareholders.table("historyTable");
    for(int i=0;i<table.rowCount();i++){
        String certificateNumber = table.cell(row(i).column(columnIndex(CERT_NO))).value();
        String remarks=table.cell(row(i).column(columnIndex(REMARKS))).value();
        if(StringUtils.isEmpty(remarks) && StringUtils.isNotEmpty(certificateNumber) 
           && Integer.parseInt(certificateNumber)==certNo){
            selectRow=i;
            break;
        }
    }
    if(selectRow==-1){
        fail("Couldn't find certificate number to transfer");
    }
    return selectRow;
}

// enter details on the table in the SplitDialog
private void enterSplitRowDetails(DialogFixture splitDialog, int cert, int distFrom, int distTo) {
    splitDialog.button("btnAdd").click();
    int row = splitDialog.table().rowCount();
    splitDialog.table().enterValue(row(row - 1).column(0), String.valueOf(cert));
    splitDialog.table().enterValue(row(row - 1).column(1), String.valueOf(distFrom));
    splitDialog.table().enterValue(row(row - 1).column(2), String.valueOf(distTo));
}
4

2 に答える 2

1

ええと... とても興味深い質問です。

質問には、特にロボットの統合と IO ソリューションの詳細など、あまり必要とされない詳細が含まれていると思われるため、適切な回答を提供することはできません...

とにかく、私は自分のやり方で音声の問題を少し分析してみます...

まず。スクリーンショットのコメントによると、すべての「30秒程度の一時停止」が一部で発生していることに気付くことができます。ストリーム読み取りプロセスの「選択/検索」(アプリ出力するデータを取得するなど)です。おそらくスレッドの問題であるため、おそらくあなたが思っているよりもはるかに深刻です。

コード スニペットでGuiQuery/GuiTask/GuiActionRunneクラスの使用法を見つけることができなかったので、前述のケースで「同期の問題」が発生する可能性があることをお勧めします...

第二。OK...それでもスレッドの問題である場合は、ロボットと IO のソリューションが両方とも 1 つのスレッド (メイン スレッドなど) にあることをお勧めします。これらは、JXTreeTable に 1 つの行がある場合に実行されます。" ... GUI は何らかのプロセスが完了するのを待っています...

3番目。そして再び...この問題によると

「自動チェックをオンにして、すべての Swing コンポーネントの更新が Swing の EDT (イベント ディスパッチャ スレッド) で行われていることを確認することをお勧めします。EDT に慣れていない人のために説明すると、EDT はすべての Swing ウィジェットを別のスレッドで処理および更新する責任があります。これにより、アプリケーションはユーザー ジェスチャに対する応答性を失うことはありません (簡単に言うと、EDT の詳細はこちら)。そのために、次のフックをテストに追加します。"

import org.fest.swing.edt.FailOnThreadViolationRepaintManager;
import org.junit.BeforeClass;
...
    @BeforeClass
    public static void setUpOnce() {
        FailOnThreadViolationRepaintManager.install();
    }

次のステップは、フレームまたはダイアログを起動することです。JUnit は独自のスレッドで実行されるため、EDT が適切に使用されていることを確認するために、Fest を介してフレームまたはダイアログを起動する必要があります。

import org.fest.swing.edt.GuiActionRunner;
import org.fest.swing.edt.GuiQuery;
import org.fest.swing.fixture.FrameFixture;
import org.junit.Before;
... 
    private FrameFixture testFrame; 
    private AllTypesFrame  frame;
... 
    @Before 
    public void setUp()  { 
        frame =  GuiActionRunner.execute(new GuiQuery<AllTypesFrame>() { 
            protected AllTypesFrame executeInEDT() { 
                return new AllTypesFrame(); 
            }
        }); 
        testFrame = new FrameFixture(frame); 
        testFrame.show(); 
    }

...おそらく、最初2番目のヒントで説明されている「スレッドの問題」だと思います...

結論として、明らかにある種の同期の問題であるため、テストをもう少しマルチスレッド化する必要があると言えます...

PS @sethu、デバッグを開始する前に少し指摘したい...ここでスレッドの競合が発生していると思われます(以前のヒントを参照)。Pause.pause(...)などのメソッドFinderUtilities.getDialogWithTitle(...)プロジェクト アーキテクチャ全体が表示されないため、表現されたビットに従って分析するのは困難ですが、アクション リスナーはリアルタイムで反応しますが、フェスト テストであるため、 「手動テスト」がうまくいくことは明らかです。クリックエミュレーションが発生するまでカウントダウンするためにいくつかの「タイマー」を使用するため、迷惑な遅延を行います。もちろん、それは別のスレッドを必要とするバックグラウンドプロセスです...おそらくコードUIスレッドとフェストスレッドのどこかでデバッグを注意深く監視してください。 (静的メソッド、thread.sleep などを参照) fest スレッドが UI のものをブロック (オーバーライド) できるポイント... :S ところで、どのメソッドPause.pause(...)が機能しますか?

PPS 追加情報がある場合は、私の回答にコメントしてください


私の答えが役に立ったら報告してください

于 2013-06-23T05:23:35.547 に答える
0

ロボットの設定はわかりませんが、少なくとも、使用しているロボットに idleTimeout やその他のタイムアウトを設定してみてください。デフォルトのタイムアウトは 10 秒です (org.fest.swing.core.Settings を参照)。減らした後 (最初の 1000 ミリ秒、次の 100 ミリ秒)、ロボットの動作が速くなることに気付きました。

robot().settings().idleTimeout(YOUR_TIMEOUT)

これが私のテスト設定と 1 つのテスト方法です。希望は明らかです。ここに私の前/後があります

private static int testMethodCounter = 0;
private static EmergencyAbortListener mEmergencyAbortListener;
private FrameFixture workbenchFrame;
private Robot robot2;
private static final int myIdleTimeout = 100;

@Before
public void setUp() throws Exception {
    // my workaround to be able to start the app once and reuse for all tests 
    if (testMethodCounter == 0) {
        robot2 = BasicRobot.robotWithNewAwtHierarchy();
        GuiActionRunner.execute(new GuiTask() {
            @Override
            protected void executeInEDT() throws Throwable {
                 ApplicationLauncher.application(ProgramRun.class).start();
            }
        });
    } else {
        // the second test method see all before created gui components
        robot2 = BasicRobot.robotWithCurrentAwtHierarchy();
    }
    testMethodCounter++;
    robot2.settings().idleTimeout(myIdleTimeout);

    workbenchFrame = WindowFinder.findFrame(FrameNames.WORKBENCH.getName()).withTimeout(10000)
            .using(robot2);
}

@After
public void tearDown() {
    // current window will not be closed
    robot2.cleanUpWithoutDisposingWindows();

}

@Test
public void someSmokeTest() throws Exception {

    Pause.pause(1000);
    // perform some test specific gui actions

    // here is very important moment, I need new robot because 
    // workbenchFrame.button(ButtonNames.SOME_BUTTON_NAME).click(); creates new dialog
    // which will be avilable in AWT stack after creation

    robot2.cleanUpWithoutDisposingWindows();
    robot2 = BasicRobot.robotWithCurrentAwtHierarchy();
    // the new Robot needs timeout setup
    // without this I have long breaks between gui events
    robot2.settings().idleTimeout(myIdleTimeout);

    workbenchFrame.button(ButtonNames.SOME_BUTTON_NAME).click();

    DialogFixture dialog = WindowFinder.findDialog("dialog2") 
              .withTimeout(5000).using(robot2);

    // some actions on the dialog        


    // once again next new dialog
    workbenchFrame.menuItem(MenuItemNames.NAME).click();

    robot2.cleanUpWithoutDisposingWindows();
    robot2 = BasicRobot.robotWithCurrentAwtHierarchy();
    // and idleTimeout setup once again, new Robot needs new setup
    robot2.settings().idleTimeout(myIdleTimeout);

    // next actions + assertion
}
于 2013-06-20T09:18:31.423 に答える