chris
chris

Reputation: 21

How to mock a static method call on an object in a static method?

I 'm a newie in Junit-testing but I have to test some code. I think now I know the basics of it, but I still got a problem on which I couldn't find anything on the Internet:

Here's the class I want to test:

public static void methodToTest(Label l2, Label l3, User u) {


    int first = MyDB.someMethod(u.anotherMethod()).size();
    int second = MyDB.someOtherMethod(u).size();


    if (first == 1) {
        l2.setCaption("...");
    }

    ...
}

I don't want the System to create the Integers 'first' and 'second'. Instead I just want them to be '1' so I can test if the last lines of code work properly.

MyDB is a public class with static Methods (someMethod() and someOtherMethod())

I want to test the Method methodToTest. I tried to call this method with parms and at the end compare the modified params to the expected ones.

I use Mockito and PowerMockito.

This is one of my tries:

@PrepareForTest({ClassToTest.class, MyDB.class })
@RunWith(PowerMockRunner.class)
public class Test extends PowerMockTestCase{
   PowerMockito.mockStatic(MyDB.class);
   PowerMockito.doReturn(1).when(MyDB.someMethod(u.anotherMethod()).size());
   PowerMockito.doReturn(1).when(MyDB.someOtherMethod(u).size());
   ClassToTest.methodToTest(l1, l2, u);
   assertTrue(l1.equals(l3) && l2.equals(l4));
}

The exception that I get is: 'Argument passed to when() is not a mock!'

I hope anyone can help me. I passed so many hours to solve this problem, without success.

Thank you!!!

Upvotes: 1

Views: 1495

Answers (1)

unigeek
unigeek

Reputation: 2826

As I mentioned in my comment, you have found that the static methods are an impediment to testing. So, I would suggest that you avoid static methods. Let's see what that might look like in your example:

You have some code you need to test..

public class ProductionClass {
  public static void methodToTest(Label l2, Label l3, User u) {
    int first = MyDB.someMethod(u.anotherMethod()).size();
    int second = MyDB.someOtherMethod(u).size();

    if (first == 1) {
        l2.setCaption("...");
    }

    ...
  }
}

First things first..make the static method of the production class an instance method:

public class ProductionClass {
  public void methodToTest(Label l2, Label l3, User u) {  // removed "static"
    int first = MyDB.someMethod(u.anotherMethod()).size();
    int second = MyDB.someOtherMethod(u).size();

    if (first == 1) {
        l2.setCaption("...");
    }

    ...
  }
}

Ok, so you still have coupling to static methods on MyDB. Getting rid of that one static method just made your production class a lot more testable. Here's how..you can do a couple of extract method refactorings like this:

public class ProductionClass {
  public void methodToTest(Label l2, Label l3, User u) {
    int first = getFirst();
    int second = getSecond();

    if (first == 1) {
        l2.setCaption("...");
    }

    ...
  }

  int getFirst() {
    return MyDB.someMethod(u.anotherMethod()).size();
  }

  int getSecond() {
    return MyDB.someOtherMethod(u).size();
  }
}

Now you can easily subclass that production class and override (or partial mock, if you prefer) the methods that you want to futz with..

public class TestableProductionClass extends ProductionClass {
  @Override
  int getFirst() {
    return 1;
  }

  @Override
  int getSecond() {
    return 1;
  }
}

Wouldn't make it any harder than it needs to be and introducing PowerMock tends to add complexity that I'd rather not deal with. YMMV. Good luck!

Upvotes: 1

Related Questions