Line
Line

Reputation: 1651

Java - How to test exception which never will occur?

I have Utils class with method which throws exception when given data are incorrect.

I have also Service which uses this method, but the data are always generated in way that they will be correct during call. Data are generated by another utils class.

I understand that I should throw this exception from Utils class - but I can't throw it from Service - so I have to catch it.

How can I test this, simulate this exception? All actions on this data are in private methods.

I want to avoid PowerMock, because I heard that it's a sign of bad design. So the question is, how to implement this in good design?

Upvotes: 1

Views: 786

Answers (2)

Novaterata
Novaterata

Reputation: 4789

Here is an approach where you want to introduce Dependency Injection, but for whatever reason you don't want to change legacy code.

Say you have some static utility method like so:

class Utils{
    public static Something aMethod(SomethingElse input) throws AnException{
          if(input.isValid())
              return input.toSomething();
          throw new AnException("yadda yadda");
    }
}

And you have a class that uses that utility method. You can still inject it with a FunctionalInterface.

@FunctionalInterface
interface FunctionThrowsAnException<K,V> {
    V apply(K input) throws AnException;
}

class Service {
    private final FunctionThrowsAnException<SomethingElse,Something> func;

    Service(FunctionThrowsAnException<SomethingElse,Something> func){
        this.func = func;
    }

    Something aMethod(SomethingElse input){
         try{
            return func.apply(input);
         }catch(AnException ex){
            LOGGER.error(ex);
         }
    }
}

Then use it like this:

new Service(Utils::aMethod).aMethod(input);

To test it:

new Service(x -> { throw new AnException("HA HA"); }).aMethod(input);

Upvotes: 1

Jorn Vernee
Jorn Vernee

Reputation: 33865

From your description it looks like this:

class Service {

    public void someMethod() {
        Data data = AnotherUtils.getData();

        try {
            Utils.method(data); // exception never thrown
        } catch(Exception e) {
            // how to test this branch?
        }
    }

}

The goal would be something like this:

interface DataProvider {
    Data getData();
}

interface DataConsumer {
    void method(Data data);
}

class Service {
    private final DataProvider dataProvider;
    private final DataConsumer dataConsumer;

    public Service(DataProvider dataProvider, DataConsumer dataConsumer) {...}

    public void someMethod() {
        Data d = dataProvider.getData();

        try {
            dataConsumer.method(data);
        } catch(Exception e) {

        }
    }
}

This technique is called dependency injection.

Then, when testing, you can simply provide a mock implementation for this DataProvider interface that does return faulty data:

@Test(expected=Exception.class)
public void myTest() {
    DataProvider badDataProvider = () -> new BadData(); // Returns faulty data

    Service service = new Service(badDataProvider, Utils.getConsumer());
    service.someMethod(); // boom!
}

For the non-testing code, you could simply wrap the utils classes you already have in these interfaces:

class AnotherUtils {
    public static Data getData() {...}

    public static DataProvider getProvider() {
        return AnotherUtils::getData;
    }
}

...

Service service = new Service(AnotherUtils.getProvider(), Utils.getConsumer());

Upvotes: 4

Related Questions