Simulated Mouse Click

hi together,



finally my application is finished. know i want to do some refactoring. for this i want to write more junits tests to proof that the application is still working after the refactoring.



i already wrote some tests but the problem is that i have to start the application to test most functions. that means drawing the window and all this stuff. for that i have to click on the button to choose the display settings. how can i automatically click on the button? i can't achieve that with jUnit tests



thx for any help!

You could try fest.easytesting.org

i read a bit through the homepage of FEST Swing and if im correct, they just use a awt robot to produce user inputs. thant i could just use the java.awt.robot package on my own without FEST?



i tried this code:



@Before setUp() {
controller.start();
Robot robot = new Robot();
robot.mouseMove(10,10);
}



but actually the line Robot robot = new Robot(); is never accessed during the test... why that?

I’ve used those java Robots before and they are quite handy for some simple automated testing :slight_smile:



http://java.sun.com/j2se/1.4.2/docs/api/java/awt/Robot.html

i used the same, but my problem is that every code line after controller.start() is not excecuted. not even system.out.println() or something like that

Well in that case your problem obviously lies in controller.start(). Maybe it doesn't return, maybe it cancels in error at some point - only you would know!

i dont know. normally the application works well, just the test doesn't. ist the normal method start from simplebasegame

The method SimpleBaseGame.start() doesn't return, it begins running the game loop which finishes only when the application is closed. You should execute controller.start() in a new thread.

i tried a lot of different things to start the controller in one and the test in another thread. but nothing suceeded. can you provide an example how to start the controller in a separate thread?

Or just construct your robot in the SimpleInit method :wink:



(I use a Robot constantly to 'auto-gain' the focus on the gfx panel, so I know it works nicely…)

but i need the robot only for my test cases. and implement code only to allow tests isn't really a good idea

uhh… then construct it BEFORE the start method somewhere…



EDIT:

Although, I KINDA see your idea.  Try this, write a STATIC class, then have an init method that only creates the robot once, then after the start method call your robot to click (this might be easier to get w/ some pseudo code, but oh well… cant be bothered :slight_smile: )(<-- sarcarsm)…

the problem is, after the start method i can't call anything else.

hmm i think i managed the thread thing, but know i believe that the robot isnt working alright. i have the following code



public class TestBoxes {

   @Before
   public void setUp() {
      Thread thread1 = new Thread(new RunnableThread(), "thread1");
      thread1.start();
      try {
         Thread.currentThread().sleep(15000);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
      
      try {
         Robot ro = new Robot();
         ro.mouseMove(100, 200);
      } catch (AWTException e) {
         e.printStackTrace();
      }
      System.out.println("Initalization done");
   }

   @Test
   public void testIt() {
      System.out.println("Test");
   }
   
}

class RunnableThread implements Runnable {

   Thread runner;
   public RunnableThread() {
   }
   public RunnableThread(String threadName) {
      runner = new Thread(this, threadName);
      runner.start();
   }
   public void run() {
      CP_Controller controller = new CP_Controller();
      controller.init(controller);
   }
}



but the mouse isn't moving at all... :(

<-- Cleans spoon :stuck_out_tongue:


import java.awt.AWTException;
import java.awt.Component;
import java.awt.Container;
import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.lang.reflect.Method;
import javax.swing.JButton;



/**
 *
 * @author basixs
 *
 *  Automated jME tester (should work for ALL jME constructs); it auto-launches
 * a supplied Class then waits for specified time, then performs single mouse click
 * on startup dialog (if applicable), then waits for specified exitTime and exits.
 *
 * Is intended to be used from the command line or a batch process.  When ESC is pressed in simple game,
 * it calls System.exit(), which closes THIS thread and all associated threads. Therefore multiple tests on simpleGame
 * implementations  are ONLY possible if they are launched from outside the JVM (ie. batch file).  Other implementations
 * that do not call System.exit() when shutting down should not be affected by this limitation.
 *
 * Usage: java AutoGameTester.java <ClassName> (ex. java AutoGameTester jmetest.renderer.TestBox )
 *
 */
public class AutoGameTester {

    private final int clickWaitTime = 1000;        // Wait 1 second
    private final int exitWaitTime = 10000;        // Wait 10 second
    //
    private Robot robot = null;
    private Point okButtonCenter = null;

    public static void main( String[] args ) {

        if( args.length > 0 ){
            new AutoGameTester().launch( args[0] );
        }
    }

    private void launch( final String className ) {

        try{
            robot = new Robot();
        } catch( AWTException ex ){
            ex.printStackTrace();
            System.exit( -1 );
        }

        try{
            runTest( Class.forName( className, false, getClass().getClassLoader() ), null );
        } catch( ClassNotFoundException ex ){
            ex.printStackTrace();
        }
    }

    private void runTest( final Class<?> classToTest, final String[] args ) {

        // Luanch game
        new Thread() {

            @Override
            public void run() {

                try{
                    final Method method = classToTest.getMethod( "main", new Class[]{ String[].class } );
                    method.invoke( null, new Object[]{ args } );
                } catch( Exception ex ){
                    ex.printStackTrace();
                    System.exit( -1 );
                }
            }
        }.start();

        // Do Click
        new Thread() {

            @Override
            public void run() {

                try{
                    sleep( clickWaitTime );

                } catch( Exception ex ){
                    ex.printStackTrace();
                    System.exit( -1 );
                }

                Container dialog = KeyboardFocusManager.getCurrentKeyboardFocusManager().getCurrentFocusCycleRoot();
                setOkButtonCoords( dialog );
                doClick();
            }
        }.start();


        // Exit test
        new Thread() {

            int sleepCounter = 0;

            @Override
            public void run() {

                while( true ){
                    try{
                        sleep( 1000 );

                        final int seconds = ( clickWaitTime + exitWaitTime - ( sleepCounter * 1000 ) );
                        if( ( sleepCounter * 1000 ) >= clickWaitTime + exitWaitTime ){
                            System.exit( 0 );
                        } else{
                            System.out.println( (seconds / 1000)  + " seconds until close!" );
                        }
                    } catch( Exception ex ){
                        ex.printStackTrace();
                        System.exit( -1 );
                    }

                    ++sleepCounter;
                }
            }
        }.start();
    }

    private void doClick() {
        if( okButtonCenter == null ){
            return;
        }

        robot.mouseMove( okButtonCenter.x, okButtonCenter.y );
        robot.mousePress( InputEvent.BUTTON1_MASK );
        robot.mouseRelease( InputEvent.BUTTON1_MASK );
    }

    private void setOkButtonCoords( final Component component ) {

        for( final Component comp : ( (Container) component ).getComponents() ){

            if( comp instanceof JButton && ( (JButton) comp ).getText().equalsIgnoreCase( "ok" ) ){

                final JButton returnButton = (JButton) comp;

                okButtonCenter = new Point( returnButton.getLocationOnScreen() );
                okButtonCenter.x += returnButton.getWidth() / 2;
                okButtonCenter.y += returnButton.getHeight() / 2;
                return;

            } else if( component instanceof Container ){
                setOkButtonCoords( comp );
            }
        }
    }
}



There you go, that is an automated tester that you can use in from the command line (OR possibly a batch file w/ a loop to test multiples) and send in the name of the class you want to test ...


First: thanx for finally posting some code, not only does it help see what you are trying to to and what is going on; but it also shows that you are not just wanting a spoon-feeding (hence the joke at the top).

Second: WHAT THE HECK IS CP_CONTROLLER???  momoko_fan was trying to help you before, but (and this goes for everyone, including myself) help us help you!  In other words, be as descriptive and informative as possible in your posts; you never know when the smallest scrap of information helps...

ok thx i now understand where my problem was. but i think you didn't understand what im planning to do :wink: neverthelss your code helped a lot. thx !

like I said before; the greater the clarity on the part of the person posing the question, the clearer the answer

(in other words, G.I.G.O.)



Glad I could help :slight_smile:

Right you are! Nevertheless i was happy to early, it's not working perfectly:



package test;

import static org.junit.Assert.*;

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import com.jme.renderer.ColorRGBA;

import view.CP_Setting;
import constants.CP_Constants;
import controller.CP_Controller;

public class TestLineLayout {
   
   private static CP_Controller controller;
   private static Thread thread1;
   private static Thread thread2;

   @BeforeClass
   public static void setUp() throws InterruptedException, AWTException {
      
      controller = new CP_Controller();
      thread1 = new Thread(new StartUpThread(controller), "thread1");
      thread1.start();
      Thread.sleep(7000);
      
      Robot ro = new Robot();
      int x = Toolkit.getDefaultToolkit().getScreenSize().width;
      int y = Toolkit.getDefaultToolkit().getScreenSize().height;
      int width = CP_Setting.getApply().getDisplay().getWidth();
      int height = CP_Setting.getApply().getDisplay().getHeight();
      int xposition = ((x/2) - (width/2)) + CP_Setting.getApply().getDisplayX() + (CP_Setting.getApply().getWidth()/2);
      int yposition = ((y/2) + (height/2)) - CP_Setting.getApply().getDisplayY() + (CP_Setting.getApply().getHeight()/2);
      ro.mouseMove(xposition, yposition);
      ro.mousePress(InputEvent.BUTTON1_MASK);
      ro.mouseRelease(InputEvent.BUTTON1_MASK);
      
      Thread.sleep(20000);
   
      }

   @Test
   public void testNumbersOfBoxes() {
      assertEquals(controller.getBoxes().getBoxes().capacity(), 2560);
   }
   
   @Test
   public void testBoxNode() {
      assertEquals(controller.getBoxes().returnBoxNode().getQuantity(), 1981);
   }
   
   @Test
   public void testSourceFiles() {
      assertEquals(320, controller.getBoxes().getSources().capacity());
   }
   
   @Test
   public void testAuthors() {
      assertEquals(1981, controller.getBoxes().getAuthors().size());
   }
      
   @Test
   public void testLineLayout() throws InterruptedException {
      thread2 = new Thread(new LineLayoutThread(controller), "thread2");
      thread2.start();
      thread2.join();
      assertEquals(controller.getBoxes().returnBoxNode().getQuantity(), 1981);
      assertEquals(320, controller.getBoxes().getSources().capacity());
      assertEquals(CP_Constants.LAYOUT_STEP, controller.getBoxes().getLayout());
      assertEquals(true, controller.getBoxes().getDrawBoxes());
      assertEquals("wrong Layout", controller.getBoxes().getPackageName(ColorRGBA.brown));
      System.out.println("Test done!");
   }
   
   @AfterClass
   public static void tearDown() {
      thread1.interrupt();
      thread2.interrupt();
   }
}

class LineLayoutThread implements Runnable {

   private Thread runner;
   private CP_Controller controller;
   
   public LineLayoutThread(CP_Controller controller) {
      this.controller = controller;
   }
   
   public LineLayoutThread(String threadName) {
      runner = new Thread(this, threadName);
      runner.start();
   }
   
   public void run() {
      controller.getConnector().disconnectAll();
      controller.getBoxes().buildData();
      controller.getMenu().setAuthorsNoDraw();
      controller.getMenu().setDisplayBoxes(true);
      controller.getBoxes().deleteBuffer();
      controller.getMenu().resetTimeline();
      controller.getBoxes().setDrawStep(true);
   }
}



Most times, the Tests runs through quite well! but sometimes the test stops somewhere in the run method and the thread is terminated. I think thats a problem with thread synchronisation. When the thread stops than it is after detaching some childs of a node.

Does jME create there a new thread which takes over controll?

i get these exception somewhere in the buildPackagesLayout() method:



java.lang.IndexOutOfBoundsException: Index: 1973, Size: 1973
   at java.util.ArrayList.RangeCheck(ArrayList.java:547)
   at java.util.ArrayList.get(ArrayList.java:322)
   at com.jme.scene.Node.draw(Node.java:502)
   at com.jme.scene.Spatial.onDraw(Spatial.java:252)
   at com.jme.scene.Node.draw(Node.java:504)
   at com.jme.scene.Spatial.onDraw(Spatial.java:252)
   at com.jme.renderer.lwjgl.LWJGLRenderer.draw(LWJGLRenderer.java:1127)
   at controller.CP_Controller.render(CP_Controller.java:375)
   at com.jme.app.BaseGame.start(BaseGame.java:82)
   at controller.CP_Controller.init(CP_Controller.java:99)
   at test.StartUpThread.run(StartUpThread.java:19)
   at java.lang.Thread.run(Thread.java:619)



this exception is only thrown if i start the method in a separate thread like in the test code above. if i normally start my application it works all fine. any hints?

sorry for posting again, but now i really found the problem.



it seems that my method buildData() in the TestCase takes so much time, that the renderer tries to draw the data before its finished and thats why a IndexOutofBoundsException is thrown.



if i insert



if (testing) {
try {
         Thread.sleep(1000);
      } catch (InterruptedException e) {
         
      }
}



then all works fine, because the rendering is delayed engough to execute the buildData method in the test process. Since i don't want to change the code only for the test cases, my question is: is there a more sexy way to delay the rendering if im testing?

many thx for any hints