3

Take this function for example:

public static int[] mergeSort(int[] array, int lo, int hi) {
        if (lo == hi) {
            return array;
        }
    int mid = (lo + hi) / 2;
    mergeSort(array, lo, mid);
    mergeSort(array, mid, hi);
    merge(array, lo, mid + 1, hi);

    return array;
}

As you can see there is the function merge which I want to mock in my test. It is possible?

Adrian
  • 169
  • 1
  • 1
  • 12
  • 1
    It's possible using spy! See an example here (https://stackoverflow.com/questions/4860475/powermock-mocking-of-static-methods-return-original-values-in-some-particula). But some testing frameworks doesn't support spy on static methods! – rafaelim Jul 03 '17 at 17:48
  • 4
    Unit tests of static methods tend to be awkward and fragile. Limitations of mock frameworks can make it impossible. You're better off making this an instance method and injecting `merge` as a dependency. Then unit testing is very easy and robust. – Gene Jul 03 '17 at 17:50

2 Answers2

5

It is probably. But that is the wrong idea here!

You want to test a sort method. If you think you need mocking for that you are doing something seriously wrong!

That method takes an array and should return the same array - just sorted.

Thus your tests should only use that : pass in an array - and check if the output is as expected! You absolutely do not care what happens inside. You focus on testing the what -not how that is done.

So your tests look somehow like:

@Test
public void testReverseArray() {
  assertThat(Whatever.mergeSort(new int[] { 3, 2, 1 }), is(new int[] { 1, 2, 3 });
}

for example (where is is a hamcrest matcher).

In other words: if you think you have to "factor out" that call to a static method - then you are probably doing that because calling the real method gives you all kinds of trouble.

So you have to "mock" it when testing this method. But surprise, you will also have to get rid of it when you test methods that call the outer mergeSort() method.

Therefore:

  • be really careful about using the static keyword
  • as soon as you find that calling a static method turns into a problem in unit test: take that as clear evidence that you have to rework that method

Meaning: either the static call should be reworked to allow calling it within unit tests - or you get rid of the static modifier.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 1
    Well if something is wrong in `merge`, the test for merge should fail, not the `mergeSort` test, not? If we are in the `Unit Testing` land. – Cristian Jul 04 '17 at 11:08
  • 2
    @Cristian Depends. If the method is *private*, then you simply do not test it in isolation. If you have good reasons to make it public, then of course you have dedicated test cases for merge. But: even when that is the case: trying to "cut out" `merge()` when testing `mergeSort()` is the wrong approach; as outlined above. – GhostCat Jul 04 '17 at 11:13
1

Thanks guys, The reason why I want to mock is:

Let's assume the followings:

  • this function, merge (or any) will be used in 100 functions
  • merge is modified causing unexpected result
  • 100 tests are failing because merge is failing.
  • instead of having one test fail, the one who test merge function, we have 100 tests failing because merge is failing.
Adrian
  • 169
  • 1
  • 1
  • 12