3

Example code:

class MyClass {
    public void myMethod(Request request) {
        Item item = getItem();
        ItemUtilHelper.setCertainProperties(newProperty, item);
        differentClass.staticMethod(item);
    }
}

The ItemUtilHelper already has a unit test class to verify item gets properly updated.

How would I go about unit testing that differentClass.staticMethod gets called with an updated item parameter?

GhostCat
  • 137,827
  • 25
  • 176
  • 248

3 Answers3

4

Let me start by saying that the static method in and of itself is a code smell. Miško Hevery summed up it quite nicely by saying:

The basic issue with static methods is they are procedural code. I have no idea how to unit-test procedural code. Unit-testing assumes that I can instantiate a piece of my application in isolation.


If you want to use Mockito only, your problem is not solvable:

What are the limitations of Mockito

Mockito 2.x specific limitations

  • ...

  • Cannot mock static methods

  • ...

(See Mockito FAQ)


You can use PowerMock to achieve your goal. But be warned: PowerMock operates on bytecode level. This means that

  • you may not be testing exactly the same bytecode you use in production (say hello to Heisenbugs) and
  • this can screw with other tools, e.g. JaCoCo

If you still want to proceed, then what you are looking for is a Spy. You can find a tutorial on PowerMock's wiki. While not directly related, the answers to this question give some additional examples on how to create a spy of a class. A throughout example can be found on Automation Rhapsody.

Community
  • 1
  • 1
Turing85
  • 18,217
  • 7
  • 33
  • 58
  • Thanks for the response. I'm still not sure how to verify that the "item" passed to the static method has the correct fields that setCertainProperties set. – Willy willy Jun 16 '18 at 23:47
  • @Willywilly that was not your question. You asked how one would verify that `differentClass.staticMethod(...)` was called with a specific parameter. You even explicitly stated that "*The `ItemUtilHelper` already has a unit test class to verify `item` gets properly updated.*" – Turing85 Jun 16 '18 at 23:56
  • Sorry maybe I worded that poorly but yes, I'm having trouble verifying if differentClass.staticMethod(...) was called with a specific parameter. – Willy willy Jun 17 '18 at 02:38
  • [Here](https://automationrhapsody.com/verify-static-method-called-powermock/) is a throughout example. – Turing85 Jun 17 '18 at 08:40
1

In addition to what @Turing85 said it's better to refactor static methods into public non-static ones. Then, an object possessing such methods can be passed into a method or constructor as a parameter and thus easily mocked or spied on. By doing so, you easily test your method logic and don't worry about object dependencies which functionality you don't want to test at the moment.

Anatolii
  • 14,139
  • 4
  • 35
  • 65
1

Seeing how much pain you are having testing this side-effectful operation, have you considered applying the functional paradigm?

Static methods aren't smells. Quite the opposite infact. Methods with side effects, as indicated by the void keyword, are what's smelly about that code snippet. Those kinds of methods generally are really hard to test and understand (as you noticed I suppose). When dealing with effects, consider returning meaningful values (like maybe a Try or a Future depending on what your method does; have a look at vavr) instead. That is, exchange the side effect with a data structure that deals with it in a functional way (the keyword here is effectful programming in the context of functional programming). And don't mutate state (your Item) in place. Rather use immutable data structures and return a new instance with updated values (you can use lenses for this).

What you end up with is a bunch of functions for which the values they return depend only on their argument. This feature is called referential transparency: you can replace every call of that function by its value, no matter the computational context. A function exhibiting this feature is called pure. That value you can then easily define assertions against in your unit test without passing any mocks.

Rea Sand
  • 163
  • 9