0

I need to write a test using assertEquals to see how many of each coins will be returned to me when money is given and am not sure how to structure it or what info to include. Money can be inserted in the amounts of $1, $2, $5 and $10. Change returned must be in the fewest amount of coins possible.

import java.math.BigDecimal;

public class MakeChange {

BigDecimal numOfQuarters = new BigDecimal(0.00);
BigDecimal numOfDimes    = new BigDecimal(0.00);
BigDecimal numOfNickels  = new BigDecimal(0.00);

BigDecimal quarter = new BigDecimal(0.25);
BigDecimal dime    = new BigDecimal(0.10);
BigDecimal nickel  = new BigDecimal(0.05);

public MakeChange() {
}

public String changeAmount(BigDecimal amtToReturn) {
    while (amtToReturn.compareTo(quarter) >= 0) {
        numOfQuarters = amtToReturn.divideToIntegralValue(quarter);
        amtToReturn = amtToReturn.subtract(numOfQuarters.multiply(quarter));
    }
    while (amtToReturn.compareTo(dime) >= 0) {
        numOfDimes = amtToReturn.divideToIntegralValue(dime);
        amtToReturn = amtToReturn.subtract(numOfDimes.multiply(dime));
    }
    while (amtToReturn.compareTo(nickel) >= 0) {
        numOfNickels = amtToReturn.divideToIntegralValue(nickel);
        amtToReturn = amtToReturn.subtract(numOfNickels.multiply(nickel));
    }
    return "You will receive: " + numOfQuarters + " Quarters " + numOfDimes + " Dimes and " + numOfNickels
            + " Nickels.";
}
}
GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 1
    Bug: `BigDecimal nickel = new BigDecimal(0.10);` – David Conrad May 29 '17 at 02:39
  • The purpose of a unit test is to verify the correctness of a previously written piece of code outside the test scope. (Or prior writing the code. See extreme programming - TDD). Point is that the unit test itself should not contain any logic. – Nico Van Belle May 29 '17 at 07:52
  • Could you give me one example of how a test would be written? I am very new to programming and am just learning Java. An example would provide a great reference to use to work from to finish the other tests. It would be greatly appreciated. – Programmer92 May 30 '17 at 00:19

1 Answers1

4

Simply spoken: you have to write testable code in order to be able to test code.

Of course, you could parse that information out of the string that this method returns. But that would be the wrong approach.

Thing is: your code is mixing two responsibilities here: A) computing how/what coins need to be returned B) turning that into a human readable message.

In other words: you start by writing another method that returns something that can easily be tested by a computer. For example by creating a class that represents change, like:

public class Change {
  public int getNumberOfQuaterts() { ...
  public int getNumberOfDimes() { ...
  ...

Now you could change your method to say:

public Change changeAmount(BigDecimal amtToReturn) { ...

and now testing becomes super-easy:

Change change = new MakeChange().changeAmount(...
assertThat(change.getNumberOfQuarters, is(5));

Beyond that:

  • You can now @Override toString() in that Change class - to create that human readable message. You can also write simple testcases then where you actually check that some predefined Change results in some exact string that you would be expecting to represent that object.
  • there are various problems in your example code. For example: there is no point in having that empty default constructor. If the constructor has nothing to do, then don't write it down. And, really important: you should not use the constructor in BigDecimal that takes a double argument. Use BigDecimal("0.01") instead! (see here). There is a reason why that constructor is @deprecated!

Finally: you could also @Override equals() in the Change class, then test code could boil down to:

assertThat(underTest.changeAmount(whatever), is(new Change(....))

You can enable yourself to manually create change objects that allow for equality checks, so that you can use assertThat() to compare change objects directly.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Great answer, I would add some "trivial" test cases as well to make sure the method can handle 0 and define what it should do with negative values. – Viktor Mellgren May 29 '17 at 07:52