Search code examples
javamavenjunittry-catchassertj

how to write the perfect code for throwable exception a negative number?Using assertThatThrownBy


I have a unit test and I want to throw an exception on it (because it will always throw in that unit test).

I am trying using try and catch but I don't know what should I do after.

In the unit test (from the first class).

@Test
void subtract_money_from_smaller_money_should_fail() {
    Money oneDinar = new Money(BigDecimal.valueOf(1));
    Money halfDinar = new Money(BigDecimal.valueOf(0.5));

    assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
        @Override
        public void call() throws Throwable {
            halfDinar.subtract(oneDinar);
        }
    }).isInstanceOf(IllegalArgumentException.class);
}

The second class where we will throw that exception.

public Money subtract(Money SubtractMoney) {
    System.out.println("TheValue of current money "+current_Money.toString());
    Money current = new Money(current_Money);
    System.out.println("TheValue of current  "+ current.current_Money.toString());
    BigDecimal subtractedNumber= BigDecimal.valueOf(0);

    try {
        subtractedNumber = current_Money.subtract(new 
        BigDecimal(String.valueOf(SubtractMoney.current_Money)));

        if (subtractedNumber.intValue() < 0) {
            // throw new IllegalArgumentException("Error the Subtracted is in minus...");
            // throw new Throwable();
        }

        //  System.out.println("TheValue of subtractedNumber" + subtractedNumber.toString());
    }

I made subtraction operation inside the try statement, and checked if that subtracted number (the new number) will be in minus (-1 or less) to throw the exception.

I tried this

throw new Throwable(); 

but didn't work (maybe I didn't use it properly).

I tried this

throw new IllegalArgumentException("Error the Subtracted is in minus...");

inside the if statement in try statement. (didn't work and I don't know if I used in proper way).

When the method in the second class is called, should throw an Exception if the money is in minus (-1 or less).

For example I want to buy an apple and it costs me 2 dollars but I gave him 1 dollar (1-2 = -1 (which activate the exception)), the seller will refuse to complete the payment (Purchase) and he will return to me my dollar and he will get the apple.


Solution

  • Your problem is on the if condition:

    if (subtractedNumber.intValue() < 0){
    

    this condition will convert the BigDecimal to int, truncating the value in case of a decimal. In your case, -0.5 will be truncated to 0, and that's why your test is not passing.

    Change this condition to

    if (subtractedNumber.doubleValue() < 0)
    

    uncomment the Illegal Arg Exception and your test will pass.

    Edit: Added more detail

    This is the code I ended with:

    public class Money {
    
        BigDecimal current_Money;
    
        public Money(BigDecimal money) {
            this.current_Money = money;
        }
    
        public Money subtract(Money subtractedMoney) {
    
            // TODO: Validation if needed
    
            BigDecimal subtractedNumber = current_Money.subtract(subtractedMoney.current_Money);
    
            if (subtractedNumber.doubleValue() < 0) {
                throw new IllegalArgumentException("Error the Subtracted is in minus...");
            }
    
            return new Money(subtractedNumber);
        }
    }
    

    Test class:

    import org.assertj.core.api.Assertions;
    import org.assertj.core.api.ThrowableAssert;
    import org.junit.Test;
    
    import java.math.BigDecimal;
    
    public class MoneyTest {
    
        @Test
        public void subtract_money_from_smaller_money_should_fail() {
            Money oneDinar = new Money(BigDecimal.valueOf(1));
            Money halfDinar = new Money(BigDecimal.valueOf(0.5));
    
            Assertions.assertThatThrownBy(new ThrowableAssert.ThrowingCallable() {
                @Override
                public void call() throws Throwable {
                    halfDinar.subtract(oneDinar);
                }
            }).isInstanceOf(IllegalArgumentException.class);
        }
    }
    

    Personally, I would verify the exception this way:

    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.jupiter.api.Assertions;
    
    public class MoneyTest {
    
        @Test
        public void subtract_money_from_smaller_money_should_fail() {
            Money oneDinar = new Money(BigDecimal.valueOf(1));
            Money halfDinar = new Money(BigDecimal.valueOf(0.5));
    
            String expectedMessage = "Error the Subtracted is in minus...";
    
            Throwable exception = Assertions.assertThrows(IllegalArgumentException.class, ()
                    -> {
                halfDinar.subtract(oneDinar);
            });
    
            Assert.assertEquals(expectedMessage, exception.getMessage());
        }
    }
    

    Both are working as expected.