Hi there,

I have developed a pool game for a project but am required to do some JUnit testing to finish it off but I have not been shown any in my course and as a result I am totally confused with how to do this. My lecturer won't give me any guidance and I can not get any help which will push me in the right direction. I am hoping that some of you guys can give me some help.

I have checked on the internet for things but I cannot find anything that resembles anything that I am doing at the moment.

I would like to know what I should be testing and just as importantly how the test code should be written. I am only displaying 1 class as I feel that if I can get help with just this class then I should be able to do testing for the other classes myself.

I know that there is a lot of code here and that it is a cheek and a lot to expect for someone to look over this much code in their spare time but I am at my wits end and completely desperate. I wouldn't dream of asking this if I wasn't.

I would really appreciate and welcome your help and suggestions as I have nowhere else to turn at this moment.

Thanks in advance

LJ

Here is my applet class:

import java.applet.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;

import javax.swing.JOptionPane;

public class PoolHustler extends Applet implements Runnable, MouseListener, MouseMotionListener{

    Scanner input = new Scanner(System.in);
    Thread mainThread;
    private static final long serialVersionUID = 1L;
    int mouseX;
    int mouseY;
    int previousBallsPotted = 0;
    public static int BALLS_POTTED = 0;
    private Image i;
    private Graphics doubleBuffer;
    Ball b[] = new Ball[16];
    Ball p[] = new Ball[6];
    Vector2 collision;
    boolean mouseDrag = false;
    double xPressPosition,yPressPosition;
    double initialSpeed;
    double initialDirection;
    boolean shotTaken = false;
    public static String player1, player2, currentPlayer;
    Vector2 initialVelocity;

    public void init()
    {
        setSize(400, 600);
        setBackground(Color.GREEN);
        addMouseListener(this);
        addMouseMotionListener(this);
    }

    public void start()
    {
        b[0] = new Ball(200,425,0,0);
        b[1] = new Ball(200, 140, 0, 0);
        b[2] = new Ball(190, 120, 0, 0);
        b[3] = new Ball(210, 120, 0, 0);
        b[4] = new Ball(180, 100, 0, 0);
        b[5] = new Ball(200, 100, 0, 0);
        b[6] = new Ball(220, 100, 0, 0);
        b[7] = new Ball(170, 80, 0, 0);
        b[8] = new Ball(190, 80, 0, 0);
        b[9] = new Ball(210, 80, 0, 0);
        b[10] = new Ball(230, 80, 0, 0);
        b[11] = new Ball(160, 60, 0, 0);
        b[12] = new Ball(180, 60, 0, 0);
        b[13] = new Ball(200, 60, 0, 0);
        b[14] = new Ball(220, 60, 0, 0);
        b[15] = new Ball(240, 60, 0, 0);

        p[0] = new Ball(2, 2, 0, 0);
        p[1] = new Ball(2, 295, 0, 0);
        p[2] = new Ball(2, 590, 0, 0);
        p[3] = new Ball(387, 2, 0, 0);
        p[4] = new Ball(387, 295, 0, 0);
        p[5] = new Ball(385, 590, 0, 0);

        collision = new Vector2(0.0, 0.0);
        mainThread = new Thread(this);
        mainThread.start();

        player1 = JOptionPane.showInputDialog("Please enter the name of Player 1: ");
        player2 = JOptionPane.showInputDialog("Please enter the name of Player 2: ");
        currentPlayer = player1;
    } 

    public void run()
    {
        while(true){

            for(int i= 0; i <= 15; i++)
                if(b[i] != null)
                    b[i].update(this);

            collision.update(this, b, p);
            repaint();

            if(!anyBallMoving(b) && b[0].getVelocity().magnitude() == 0 && shotTaken)
            {
                shotTaken = false;
                currentPlayer = playerTurn();
            }

            try
            {
                Thread.sleep((int)1000f/60);
            }
            catch(InterruptedException e){

                try
                {
                    mainThread.sleep(60000000);
                }
                catch(InterruptedException ie){
                }
            }
        }
    }

    public void update(Graphics g)
    {
        if(i == null)
        {
            i = createImage(this.getSize().width, this.getSize().height);
            doubleBuffer = i.getGraphics();
        }

        doubleBuffer.setColor(getBackground());
        doubleBuffer.fillRect(0, 0, this.getSize().width, this.getSize().height);
        doubleBuffer.setColor(getForeground());

        paint(doubleBuffer);

        g.drawImage(i, 0, 0, this);
    }

    public void paint(Graphics g)
    {
        g.setColor(Color.BLACK);
        g.drawLine(0, 425, 400, 425);
        g.drawArc(100, 335, 180, 180, 180, 180);

        Color[] colours = {Color.WHITE, Color.RED, Color.YELLOW, Color.RED, Color.RED,
                           Color.BLACK, Color.YELLOW, Color.YELLOW, Color.RED, Color.YELLOW,
                           Color.RED, Color.YELLOW, Color.RED, Color.YELLOW, Color.RED,
                           Color.YELLOW};

        for(int i = 0; i < colours.length; i++)
            if(b[i] != null)
                b[i].display(g, colours[i]);

        for(int i = 0; i<p.length; i++)
            p[i].drawPockets(g);

        if(Math.abs(mouseX-b[0].getX()) < 50&&Math.abs(mouseY-b[0].getY())<50 )
            b[0].drawCue(g,mouseX,mouseY);      

        Font font = new Font("Serif", Font.BOLD, 18);
        g.setFont(font);
        g.setColor(Color.BLACK);
        g.drawString(currentPlayer, getWidth() - 101, 26);
        g.setColor(Color.BLUE);
        g.drawString(currentPlayer, getWidth() - 100, 25);
    }

    public String playerTurn()
    {
        if(previousBallsPotted == BALLS_POTTED)
            currentPlayer = (currentPlayer.equals(player1) ? player2 : player1);
        else
            currentPlayer = (currentPlayer.equals(player1) ? player1 : player2);
        return currentPlayer;
    }

    public void mouseDragged(MouseEvent e) {}

    public void mouseMoved(MouseEvent e)
    {
        mouseX = e.getX();
        mouseY = e.getY();
    }

    public void mouseClicked(MouseEvent e)
    {
        mainThread.interrupt();
    }

    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}

    public void mousePressed(MouseEvent e)
    {
        if(!mainThread.isInterrupted())
        {
            xPressPosition = e.getX();
            yPressPosition = e.getY();

        if(xPressPosition - b[0].getX() > Ball.getRadius() || yPressPosition - b[0].getY() > Ball.getRadius())
            System.out.println("The mouse press must happen on the cue ball only!!!");
        else if(b[0].getVelocity().magnitude()!=0)
            System.out.println("Can't take a shot while cue ball is still moving!");
        else if (anyBallMoving(b))
        {
             System.out.println("Can't take a shot while a ball is moving!");
        }
        else
            mouseDrag = true;
        }           
    }

   private boolean anyBallMoving(Ball[] b)
   {
       for(int i=1;i<b.length;i++)

                if(b[i]!=null && b[i].isMoving())
                {   
                    return true;
                }

       return false;
   }

   public void mouseReleased(MouseEvent e)
   {
        double dragDistance = 0;

        if(mouseDrag == true) 
        {
            double xReleasePosition = e.getX();
            double yReleasePosition = e.getY();

            dragDistance = Math.sqrt((Math.pow(xPressPosition-xReleasePosition,2) + Math.pow(yPressPosition-yReleasePosition,2 )));
            System.out.println("Drag distance is " + dragDistance);

            initialSpeed = dragDistance; 
            System.out.println("Initial speed is " + initialSpeed);

            initialDirection = Math.toDegrees(Math.atan(-(b[0].getY() - e.getY())/(b[0].getX()-e.getX())));

        if(initialDirection<0 && e.getY() > b[0].getY())
            initialDirection+=180;

        else if(e.getY()<b[0].getY()&&e.getX()>b[0].getX())
            initialDirection+=180;

        else if(e.getY()<b[0].getY()&&e.getX()<b[0].getX())
            initialDirection+=360;
            System.out.println("Initial direction is " + initialDirection);
            initialVelocity = new Vector2(initialSpeed*Math.cos(Math.toRadians(initialDirection)),initialSpeed*Math.sin(Math.toRadians(initialDirection)));
            System.out.println("Initial velocity is " + initialVelocity);

            double initialVelXNormalised;
            double initialVelYNormalised;

        if(Math.abs(initialVelocity.getX())>=Math.abs(initialVelocity.getY()))
        {
            initialVelXNormalised = (initialVelocity.getX()/Math.abs(initialVelocity.getY()));
            initialVelYNormalised = 1;
        }
        else
        {
            initialVelXNormalised = 1;
            initialVelYNormalised = (initialVelocity.getY()/Math.abs(initialVelocity.getX()));
        }
        b[0].setDeltaX(initialVelocity.getX()*0.6);  
        b[0].setDeltaY(-initialVelocity.getY()*0.6);
        b[0].setNormalisedDeltaX(initialVelXNormalised);
        b[0].setNormalisedDeltaY(-initialVelYNormalised);

        Vector2 initialVelocityNormalised = new Vector2(initialVelXNormalised,initialVelYNormalised);
        b[0].setVelocity(initialVelocity);
        }
        mouseDrag = false;
        previousBallsPotted = BALLS_POTTED;
        shotTaken = true;
    }
}

First step to unit testing is to make your code testable. I'll give you one example. In your mouseReleased method you have a lot of code that does some calculations and set some variables. What you could do here to make the code more testable is to move out the code into a new method that takes some input and procudes some output that is used to set the variables you want to set. It is best if the method does not have any side effects, i.e. everything that the method does has a local scope.

Then when you write your unit test you can test that single method to see if the input produces the desired output using relevant input data and expected outcome.

This is just a quick observation of your code, I'm not sure if what i suggested is applicable in this exact case. You can of course unit test without doing this but it might make life paintful as you will need to mock mouse events etc...

What you need to do is to download junit (junit4 preferably), how it is used depends on your dev environment. To write a junit test, simply create a test class, call it whatever you like and create your test method. In junit4 you annotate your method to tell junit that it is a test. For example

public class ATestClass {

    // This is one test, you can make as many as you like
    @Test
    public void testSomething() {
        ....
    }

    @Test
    public void testSomethingElse() {
        ....
    }

    @Before
    public void setupTheTest() {
        // Use the Before annotation if you need to initialize variables, object etc..
    }

    @After
    public void tearDownTheTest() {
        // Use the After annotation if you want to do something after the tests are done... Usually not needed.
    }

}

You then just run this class using junit and junit will run the tests for you. It is easier if your using an IDE like eclipse to develop.

Here a junit link that goes through the basics quickly: http://www.cavdar.net/2008/07/21/junit-4-in-60-seconds/

You might also want to take a look at mockito (google it if youre interested), which is a library that lets you create mock objects and stuff so you dont have to implement intire interfaces etc. It is useful if the code you're testing has a lot of dependencies to other classes. It also provides some nice features that makes testing easier.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.