1

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?

Line
  • 1,529
  • 3
  • 18
  • 42
  • I'm not clear what exactly you want to test. The `Utils`, the `Service`, or both in conjunction with each other? – Joe C Jun 17 '17 at 15:30
  • 1
    Just Mock your Utils class. You should be able to mock it without Powermock. – Guillaume F. Jun 17 '17 at 15:30
  • 1
    You can inject the Utils.method, even with a FunctionalInterface then mock it and have the mock throw the exception – Novaterata Jun 17 '17 at 15:33
  • Using PowerMock isn't bad, having the need for it can be an indicator your design is bad (if what you've heard is true). Not using it doesn't suddenly make your design good. – Jorn Vernee Jun 17 '17 at 15:34
  • @JoeC, I want to test Service. – Line Jun 17 '17 at 15:35
  • @GuillaumeF., Utils methods are static. – Line Jun 17 '17 at 15:36
  • @JornVernee ok, but this problem can be sign that something is bad with my design - I would like to know what is it and how can I fix t. – Line Jun 17 '17 at 15:37
  • @Novaterata you mean I should create some interface to Utils class? It's not clear at all for me. – Line Jun 17 '17 at 15:39
  • 1
    You can also use reflection to get access to the private methods – Gareth Jordan Jun 17 '17 at 15:40
  • 3
    Ah, static methods. I think we've just found your potential "indicator your design is bad". – Joe C Jun 17 '17 at 15:42
  • @JoeC, utils class with static methods are bad? For example, if I need XML marshalling and unmarshalling, which will be used by multiple classes, I should create regular XmlUtils class and each time create instance to call some method which have nothing in common with particular instance? Where is the sense of something like that? – Line Jun 17 '17 at 15:48
  • @GarethJordan I assume that this is as bad as using PowerMock. – Line Jun 17 '17 at 15:51
  • Not really, I'm on my phone so it's hard to type out an example but look at https://en.m.wikipedia.org/wiki/Reflection_(computer_programming) – Gareth Jordan Jun 17 '17 at 15:59
  • @Line Joe is referring to the testability of static methods. You can't use DI, so you can't easily interact with a mocked version via strategy. OT: You could use Mockito's `when(Utils.someMethod()).doThrow(new Exception())` – Vince Jun 17 '17 at 16:02
  • @GarethJordan I think I have some clue what is reflection. But on fast I type "reflection unit tests" on Google and in highest voted answer to this question (https://stackoverflow.com/questions/2811141/is-it-bad-practice-to-use-reflection-in-unit-testing) you can find something very similar to what they say about PowerMock: "If you are testing your own code, the fact that you need to use Reflection means your design is not testable, so you should fix that instead of resorting to Reflection." – Line Jun 17 '17 at 16:02
  • @VinceEmigh, what is DI, what is OT, what is strategy? As far as I know, I can't put static method to Mockito "when". – Line Jun 17 '17 at 16:05
  • 1
    @Line You could say the same about persistent frameworks using reflection to instantiate objects. Reflection is useful when special requirements exist. In this case, if the methods are better fit as utility methods, it may be more beneficial to use reflection in your tests to keep your production code on par with requirements. How do you think frameworks like Mockito work? – Vince Jun 17 '17 at 16:06
  • 1
    @Line You could use PowerMock. Sorry for the misdirection, I haven't used Mockito or PowerMock in a while, they kinda blend now. Pretty sure PowerMock has a `mockStatic`. DI is [Dependency Injection](https://en.m.wikipedia.org/wiki/Dependency_injection), OT is On Topic (a suggestion for your post) – Vince Jun 17 '17 at 16:10
  • I disagree, if you want to independently unit test a private method on a class. However in your case the service class makes a call to the Utilities class bus a method that is not private, so you should be able to pass "invalid" input to that method which would in turn call the private method with the invalid input and trigger the exception – Gareth Jordan Jun 17 '17 at 16:19
  • @GarethJordan, I heard that the private methods should only be tested by public :) Unfortunately I can't do this. The problem is that I pass the object to this method, and every instance of this object will be valid for this method. – Line Jun 17 '17 at 16:31
  • @VinceEmigh, thanks for explanation. I know I can do this with PowerMock, I mention in question that I'm looking for another methods. – Line Jun 17 '17 at 16:31
  • 1
    @Line It's not bad design, nor does it suggest badly designed code. Yes, it can be abused and allow badly designed code to be tested, but that doesn't mean it should be avoided altogether. `default` methods can be abused, but that doesn't mean they should be avoided - they have a purpose. I don't know the full usage details of `Utils#method`, but it's possible to run into other design issues by switching from `static` to DI, which isn't worth it just for testing. What if you wanted to test a static factory that relied on private class members? – Vince Jun 17 '17 at 16:57
  • 1
    @Line what I mean is either you replace what I assume is some static utility method with something that can be injected OR in Java 8 you can inject any single method using a FunctionalInterface like the ones in java.utils.function. Since you need to throw a checked exception. You can create your own single method Interface that has the exact same signature as your static method and put `@FunctionalInterface` on it. Then you can use any lambda that matches that signature. – Novaterata Jun 17 '17 at 18:27

2 Answers2

4

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());
Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93
  • Thanks. But is it wort so much code only to test couple of lines which shoulnd't ever be used by production code, if there will be no problem with another classes? :/ – Line Jun 17 '17 at 16:03
  • 2
    @Line You don't just gain testability, you gain maintainability. If you for instance want to use different data providers in different situations, you don't have to refactor your `Service` class. Of course, another alternative is to just not test that branch. – Jorn Vernee Jun 17 '17 at 16:06
  • 3
    The D in SOLID is actually [Dependency *Inversion*](https://en.m.wikipedia.org/wiki/Dependency_inversion_principle), which refers to decoupling modules via abstraction. Dependency injection tends to rely on dependency inversion (like in this case), but it's not a requirement (for example, injecting `String`). Dependency injection isn't accounted for with SOLID – Vince Jun 17 '17 at 16:18
  • @VinceEmigh Thanks, I confused the two. I keep remembering Dependency inversion as inversion of control, which doesn't start with a D. – Jorn Vernee Jun 17 '17 at 16:19
  • If you make the DataConsumer a FunctionalInterface than Utils.getConsumer() doesn't need to be implemented. A lambda that uses Utils.method can be used instead without modifying that code. – Novaterata Jun 17 '17 at 18:29
1

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);
Novaterata
  • 4,356
  • 3
  • 29
  • 51