Search code examples
javamethodscallinstance-variables

How do I test my method in another class?


I just started taking Computer Science (Java) about 5 weeks ago and I am still having trouble creating methods. I was assigned to create an NFL statistic class and then create a method to show a calculation. Everything went smooth until I went to call my method in a test class. What seems to be missing here?

NFLPlayer CLASS (Containin the method):

private int touchdowns;
private int interceptions;
private int passingAttempts;
private int completedPasses;
private int passingYards;
private int runningYards;
private int recievingYards;
private int tackles;
private int sacks;


// Method for Quarterback rating
public double QBRating(int touchdowns, int passingAttempts, int completedPasses,
        int passingYards, int interceptions) {

        double a = (completedPasses / passingAttempts - 0.3) * 5;
        double b = (passingYards / passingAttempts - 3) * 0.25;
        double c = (touchdowns / passingAttempts) * 25;
        double d = 2.375 - (interceptions / passingAttempts * 25);
        double ratingQB = ((a + b + c + d) / 6) * 100;
        {
        return ratingQB;
        }   

}

Now here is my test class where I am having trouble displaying my calculations

class MyTest {
public static void main(String[] args) {

    NFLPlayer playerStats = new NFLPlayer();

    //Player1 finding quarterback rating
    int touchdowns = 2;
    int passingAttempts = 44;
    int passingYards = 285;
    int interceptions = 1;
    int completedPasses = 35;

    // Call QB rating method
    playerStats.QBRating(touchdowns, passingAttempts, completedPasses,
            passingYards, interceptions); 

    System.out.println(QBRating);
}

}


Solution

  • Instead of passing so many int arguments (easy to mix them up) to your method you could give your NFLPlayer class private fields for each value:

    public class NFLPlayer {
    
        private final String name;
    
        private int touchdowns;
        private int passingAttempts;
        private int completedPasses;
        private int passingYards;
        private int interceptions;
    
        public NFLPlayer(String name) {
            this.name = name;
        }
    
        // Method names start with a lower case character in Java
        // The name should usually be an imperative 'do something' not a noun ('something')
        // although there are exceptions to this rule (for instance in fluent APIs)
        public double calculateQbRating() {                
            double a = (completedPasses / passingAttempts - 0.3) * 5.0;
            double b = (passingYards / passingAttempts - 3.0) * 0.25;            
            // an AritmeticException will occur if passingAttempts is zero
            double c = (touchdowns / passingAttempts) * 25.0;
            double d = 2.375 - (interceptions / passingAttempts * 25.0);
            return ((a + b + c + d) / 6.0) * 100.0;
        }       
    
        public String getName() {
            return  name;
        }
    
        // setter for the touchdowns field
        public void setTouchdowns(int value) {
            touchdowns = value;
        }
    
        // TODO: add other setters for each private field
    
        @Override
        public String toString() {
            return String.format("Player %s has QB rating %s", name, calculateQbRating());
        }
    }
    

    Your application (this is not called a test):

    class NFLApplication {
    
        public static void main(String[] args) {      
    
                NFLPlayer playerStats = new NFLPlayer("johnson");    
    
                playerStats.setTouchdowns(2);
                playerStats.setPassingAttempts(44);
                playerStats.setPassingYards(285);
                playerStats.setInterceptions(1);
                playerStats.setCompletedPasses(35);
    
                double qbRating = playerStats.calculateQbRating();    
    
                System.out.println(qbRating);
            }
    }
    

    A test for your NFLPlayer class using the JUnit framework (JUnit is usually included by default within your IDE):

    public class NFLPlayerTest {
    
        // instance of the class-under-test
        private NFLPlayer instance;
    
        // set up method executed before each test case is run
        @Before
        public void setUp() {
            instance = new NFLPlayer(); 
        }
    
        @Test
        public void testCalculateQbRatingHappy() {
            // SETUP
            instance.setTouchdowns(2);
            instance.setPassingAttempts(44);
            instance.setPassingYards(285);
            instance.setInterceptions(1);
            instance.setCompletedPasses(35);
    
            // CALL
            double result = playerStats.calculateQbRating();  
    
            // VERIFY
            // assuming here the correct result is 42.41, I really don't know
            assertEquals(42.41, result);
        }
    
        @Test
        public void testCalculateQbRatingZeroPassingAttempts() {
            // SETUP
            // passingAttempts=0 is not handled gracefully by your logic (it causes an ArithmeticException )
            // you will probably want to fix this 
            instance.setPassingAttempts(0);
    
            // CALL
            double result = playerStats.calculateQbRating();  
    
            // VERIFY
            // assuming here that you will return 0 when passingAttempts=0
            assertEquals(0, result);
        }
    }
    

    This test class should go in your test source directory (normally in yourproject/src/test/yourpackage/). It requires some imports which should be easily resolvable within the IDE since JUnit is usually available by default.

    To run the test, right click on it and select something like 'Run test', 'Test file' or the like, depending on which IDE you are using (IDE's are development tools such as Eclipse, NetBeans or IntelliJ). You should see some test output indicating if the test succeeded (green) or if there were failures (red). Having such tests is useful because it forces you think about your design and write better code. (testable code is usually better than hard-to-test code) and because it warns you if new changes cause bugs in existing code (regression).

    EDIT:

    To create two players with different stats you have to create two instances (I added a name field so we can more easily distinguish the players):

    NFLPlayer player1 = new NFLPlayer("adams");
    NFLPlayer player2 = new NFLPlayer("jones");
    

    And give them each their own statistics:

    player1.setTouchdowns(2);
    player1.setPassingAttempts(4);
    player1.setPassingYards(6);
    player1.setInterceptions(8);
    player1.setCompletedPasses(10);
    
    player2.setTouchdowns(1);
    player2.setPassingAttempts(3);
    player2.setPassingYards(5);
    player2.setInterceptions(7);
    player2.setCompletedPasses(9);
    

    You could even create a list of players:

    List<NFLPlayer> players = new ArrayList<>();
    players.add(player1);
    players.add(player2);
    

    And then you could for instance print out all player ratings in a loop:

    for(NFLPlayer player : players) {
        // this uses the `toString` method I added in NFLPlayer
        System.out.println(player);
    }