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);
}
}
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);
}