Static class/method/property in unit test, stop it or not

41,581

Solution 1

Testing static method is no different than testing any other method. Having static method as a dependency inside another tested module raises problems (as it's been mentioned - you can't mock/stub it with free tools). But if the static method itself is unit tested you can simply treat it as working, reliable component.

Overall, there's nothing wrong (as in, it doesn't disrupt unit testing/TDD) with static methods when:

  • it is simple, input-output method (all kinds of "calculate this given that")
  • it is reliable, by what we mean it's either unit tested by you or comes from 3rd party source you consider reliable (eg. Math.Floor might be considered reliable - using it shouldn't raise "Look out, it's static!" warning; one might assume Microsoft does its job)

When static methods will cause problems and should be avoided? Basically only when they interact with/do something you cannot control (or mock):

  • all kind of file system, database, network dependencies
  • other (possibly more complex) static methods called from inside
  • pretty much anything your mocking framework can't deal with on regular terms

Edit: two examples on when static method will make unit testing hard

1

public int ExtractSumFromReport(string reportPath)
{
     var reportFile = File.ReadAllText(reportPath);
     // ...
}

How do you deal with File.ReadAllText? This will obviously go to file system to retrieve file content, which is major no-no when unit testing. This is example of static method with external dependency. To avoid that, you usually create wrapper around file system api or simply inject it as dependency/delegate.

2

public void SaveUser(User user)
{
    var session = SessionFactory.CreateSession();
    // ...
}

What about this? Session is non-trivial dependency. Sure, it might come as ISession, but how do force SessionFactory to return mock? We can't. And we can't create easy to detemine session object either.

In cases like above, it's best to avoid static methods altogether.

Solution 2

Static methods CAN be unit tested. They can't be mocked (generally; there are some frameworks to do this like Moles.

Solution 3

You can't mock static methods/properties. So, when your classA uses some static member of classB you can't test classA in isolation.

UPDATE: I don't see any problem of wrapping some static class into object. It doesn't take lot of time, but it allows you to decrease coupling in your system.

Share:
41,581
Pingpong
Author by

Pingpong

Updated on July 03, 2020

Comments

  • Pingpong
    Pingpong almost 4 years

    Should a static class/method/property be used in a unit test development environment, given that there is no way to test it without introducing a wrapper that is again not testable?

    Another scenario is that when the static members are used within the unit tested target, the static member cannot be mocked. Thus, you have to test the static members when the unit tested target is tested. You want to isolate it when the static member performs calculation.

  • undefined
    undefined about 12 years
    But this is overkill for simple cases. Moles integrates in build process and available only for .net
  • Pingpong
    Pingpong about 12 years
    what about when the static method performs calculation, and you cannot mock it? Does it require to make it instance method?
  • k.m
    k.m about 12 years
    @Pingpong: Could you expand a bit? Math.Floor performs calculations - do we mock it? No, because we know Math.Floor(2.5) will return 2. When input-output is easy to determine you don't have to mock anything (or use instance). The whole static method makes testing hard comes from situations when they provide non-trivial dependencies or have side effects. See my edit.
  • Pingpong
    Pingpong about 12 years
    What about the static method is a custom method that performs long process calcuation?
  • k.m
    k.m about 12 years
    @Pingpong: unit tests should execute fast. If something is slowing them, it most likely should be abstracted. Or simply do an integration test instead (tho in most cases you will need both).
  • Pingpong
    Pingpong about 12 years
    Good examples (1,2). If we only use instance members when possible, why we need both?
  • Tarik
    Tarik about 9 years
    I like this type of approaches more than simply do not do this approaches. There are cases when static methods are good options and if you are a careful developer, you will always keep Implications of your choices in mind when writing code. Otherwise, even a simple thing can be deadly in the hands of careless novice developer.
  • ACV
    ACV over 4 years
    I think this is the best answer! The emphasis should be this: if the static method itself is unit tested you can simply treat it as working, reliable component. So this means you don't need to mock it, just let the code under test call it as it is. However, this means you'll have to prepare potentially more data in your test..