0

I have a helper class which contains an public static method getProductHandler(String name):

public class ProductHandlerManager {
  public static Handler getProductHandler(String name) {
        Handler handler = findProductHandler(name);
        return handler;
  }
}

A CustomerService class uses the above ProductHandlerManager:

public class CustomerService {
   ...
   public void handleProduct() {
     Handler appleHandler = ProductHandlerManager.getProductHandler("apple");
     appleHandler.post(new Runnable() {
        @Override
        public void run() {
           //...
        }
     });
   }
}

I want to unit test handleProduct() method in CustomerService class. I tried using mockito to mock the ProductManager.getProductHandler("apple") part in test, however, mockito doesn't support static method mocking. How can I use Mockito to unit test handleProduct() function then?

Please don't suggest me to use Powermock, since I read some article which says if I need to mock static method, it indicates a bad design. But I can accept suggestions about code refactoring to make it testable.

user842225
  • 5,445
  • 15
  • 69
  • 119
  • This question was already answered in your original question http://stackoverflow.com/questions/33606719/missingmethodinvocationexception-from-mockito-when-do-unit-test/33606767?noredirect=1#comment54994764_33606767. Make it an instance (non-static) method. – Jaroslaw Pawlak Nov 09 '15 at 13:34
  • I'd like to see if there is an alternative solution (keep that method static). E.g. through code refactoring – user842225 Nov 09 '15 at 13:36
  • 1
    No, there isn't. You can change the method to non-static, use PowerMock (not recommended) or you could create a delegate non-instance method and mock it instead (work around usually when working with legacy code). – Jaroslaw Pawlak Nov 09 '15 at 13:39
  • `non-instance` method ? What does that mean? `non-instance` == `static` ? – user842225 Nov 09 '15 at 13:41
  • typo, a meant `instance` method, i.e. `non-static` – Jaroslaw Pawlak Nov 09 '15 at 14:29
  • I assume that you actually should not change your production code to meet the testing needs. – Rufi Nov 09 '15 at 14:38
  • Actually, if you haven't written your tests first, then sometimes attempting to write tests afterwards reveals some design flaws or weaknesses that ought to be addressed by changing production code. But agreed that it's generally unwise to make your production code less well-designed in order to meet a testing need is a bad idea. – Kevin Welker Nov 10 '15 at 17:14

1 Answers1

0

You can refactor and specify a Handler yourself. These can often be package private, if you put your tests in the same package as your classes-under-test—even if they're in a different source folder (e.g. src vs testsrc). Guava (Google Commons) has a handy @VisibleForTesting documentation annotation, too, though Javadoc tends to work as well.

public class CustomerService {
  public void handleProduct() {
    handle(ProductHandlerManager.getProductHandler("apple"));
  }

  /** Visible for testing. */
  void handleProduct(Handler handler) {
    handler.post(new Runnable() {
       @Override
       public void run() {
          //...
       }
    });
  }
}

At this point, you can test handleProduct(Handler) intensively as a unit test, then only test handleProduct() as an integration test to ensure the "apple" product handler interacts correctly.

Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251