Your idea of introducing an interface or wrapper class seems correct to me. By depending on an interface, you can avoid the dependency on the static class. The interface can be implemented by a class that just forwards the requests to the static privilege checker, and by other classes that serve testing purposes.
But like I mentioned this PrivilegeChecker class is hundreds of methods and I am not about to create a giant wrapper around that. So where to start?
By introducing an interface that only covers the methods that you need. There is no need for your code to depend on all the other methods, so the interface used by your code shouldn't declare them.
There are two ways to look at an
interface in the OOP sense:
- from the implementer perspective
- from the user perspective
You have the implementer perspective that you're trying to abstract over a class with hundreds of methods. But from the perspective of a user of this interface, only a handful methods are needed – a much smaller and much more accurate description of the real interface. This idea, that interfaces are declared by users, enables dependency inversion. It occurs in various patterns like the “staircase pattern” or the “onion architecture”.
It seems creating a wrapper class around just a single method also seems excessive because it might eventually end up in hundreds of classes.
On one hand, this might not matter. Modern C# makes it very easy to create lots of small classes.
But more pragmatically, you might have a point. Serious dependency inversion leads to having lots of interfaces, lots of moving parts, that are unnecessary during normal execution. This makes the code more complicated and more fragile. So maybe the best approach is to create that interface with hundreds of methods after all?
There are however two strategies that might help limit this effort.
That the privilege checker has hundreds of methods does suggest that something has gone a bit wrong design-wise. It is very likely that these methods can be grouped in a reasonable manner, and that it could be decomposed into smaller interfaces that still are cohesive.
For example, an application might have largely separate sets of privileges relating to admin tasks versus ordinary user actions. The code that deals with ordinary user actions should not have to depend on admin-only privileges. If the feature you're working on only relates to user-only actions, a lot of methods would already be out of scope for the interface you'd have to write.
I suspect that classes/interfaces that have only a single method, or those that have hundreds of methods, are both suboptimal in your scenario. The best design is probably somewhere in between. A dozen interfaces of a dozen methods each is probably easier to manage. But this is NOT about the size or the number of interfaces, but about ensuring that each interface is cohesive.
Your interfaces don't have to be all-or-nothing. You can start with just the methods you need. Later, when other parts of the code want to use a similar testing/mocking strategy, the interface can be expanded to also cover those methods that this other code needs.
The big advantage of working on an application (as opposed to a library with a public API) is that you can always refactor the internals. You don't have to start with a perfect design, and can instead take incremental steps. You can add more methods to an interface later because you also control all classes that implement the interface.
So unless the rest of the team has objections to that design, I would indeed start with creating an interface with the single method that you need right now.