2

I have a static wrapper class for the android Log.

It looks like this (simplified):

// Source: https://github.com/ccrama/Slide/blob/master/app/src/main/java/me/ccrama/redditslide/util/LogUtil.java
public class LogUtil {
    private static final int CALLING_METHOD_INDEX;    

    static {
        int i = 1;
        for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
            i++;
            if (ste.getClassName().equals(LogUtil.class.getName())) {
                break;
            }
        }
        CALLING_METHOD_INDEX = i;
    }

    public static String getTag() {
        final StackTraceElement ste = Thread.currentThread().getStackTrace()[CALLING_METHOD_INDEX];
        return "(" + ste.getFileName() + ":" + ste.getLineNumber() + ")";
    }

    public static void v(String message) {
        Log.v(getTag(), message);
    }
}

My problem: I'm testing another method that calls this LogUtil.v()'s method.

Is there a way to test the other method with Mockito and not Powermock(ito) if possible?

Currently it throws a LogUtil.v not mocked Exception.

I read that if I have to use PowerMockito, I'm doing something wrong (=> not following TDD).

GhostCat
  • 137,827
  • 25
  • 176
  • 248
Thomas
  • 483
  • 7
  • 22
  • I think this is relevant to your question: http://stackoverflow.com/questions/4482315/why-does-mockito-not-mock-static-methods – LLL May 04 '17 at 13:03
  • @LLL Well, the second answer is that you shouldn't have to mock static methods, hence my question how to avoid it in this specific case – Thomas May 04 '17 at 13:11
  • 2
    I think that fundamental idea behind mocking (before they've added "helper" functions) was that Mock creates objects on your behalf. With static methods you don't need objects, so you don't need mocking. You can just use LogUtil.getTag() and verify that it returns valid data. But this is only my point of view, so maybe someone will have better answer. – LLL May 04 '17 at 13:14
  • @LLL I don't want to test the actual code in my OP, but a method which _calls_ this code. I made it clearer in my OP, thanks for pointing that out though :) – Thomas May 04 '17 at 13:19
  • 1
    Perhaps I'm clueless here, but what exactly is your problem when testing that other method? How does this method calling your method here prevent you from testing it? – Florian Schaetz May 04 '17 at 13:23
  • 1
    @FlorianSchaetz Such **static** init blocks always carry certain risk. Depending on the exact content, already *loading* classes with such inits might break you. That is one of the reason why **static** has such a bad reputation: if not used properly, you can make unit testing for other people much harder than it ought be. Believe me, been there. – GhostCat May 04 '17 at 14:33
  • 1
    I know what the problem is with static in general, but the question was, what the actual problem is HERE, in this example, since I do not see any code that would actually break a test, but perhaps I'm just clueless. – Florian Schaetz May 04 '17 at 14:35
  • 1
    Probably the `Log.v(getTag(), message);` ... but @FlorianSchaetz you got a point there ... – GhostCat May 04 '17 at 14:38
  • 1
    @ThomasLü You might want to enhance your question: to show how code using the static method runs into problems. In other words: try to add a [mcve] showing the "real problem" you are suffering from - what breaks your tests? – GhostCat May 04 '17 at 14:39
  • 1
    Beyond that: +1 for knowing that PowerMockito should not be used. -1 for spelling TDD as TTD. Well, just kidding. – GhostCat May 04 '17 at 14:43
  • @FlorianSchaetz After trying the now minmal code again as GhostCat proposed, I wasn't able to reproduce my problem. It looks like it was another problem and I wasn't able to spot that. Sorry for the trouble, I just wasn't testing well enough before posting here. Thanks for the link though GhostCat, haven't seen that one before :) What's the best way to close this question? – Thomas May 04 '17 at 15:00

1 Answers1

1

( disclaimer: I am one of those folks telling people to not use PowerMock(ito) )

Having said so: when you are using a 3rd party library, which you can't change, then using PowerMock(ito) can be a reasonable option.

In essence, you only got two options:

  • As said; go for the frameworks that allow mocking static methods; and that allow you to prevent such static init code to be executed within your unit-test environment. There is PowerMock(ito), and also JMockit.
  • Alternatively, you could build a small tiny wrapper around these classes; and then make sure that all your own code only works with those wrappers.

Thus you have to evaluate the pros/cons of both approaches; and pick the one that "works better" for you and your team. Me, personally, always go for option 2. But of course, that is only possible when writing new code.

In reality, a massive refactoring of the whole code-base in order to replace those static calls with your own wrapper is not something that should be approached lighthearted.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Thanks for your lengthy reply! I'm currently indeed refactoring my code to make it testable (T**D**D :D) and I'm trying to understand the basics. It looks like adding `unitTests.returnDefaultValues = true` to the build.gradle fixed it, my static wrapper wasn't the problem. – Thomas May 04 '17 at 15:02