Static Methods and Unit Tests

I read that static methods are avoided when using TDD, because they are usually difficult to mock. I believe that the easiest thing for unit test is the static method, which has simple functionality. No need to instantiate any classes, encourages methods that simply do one thing, are "autonomous", etc.

Can someone explain this discrepancy between TDD best practices and pragmatic ease?

thanks, A

+6
source share
4 answers

The static method is easy to test, but something that directly calls the static method is usually not easy to check regardless of the static method on which it depends. Using a non-static method, you can use an instance of stub / mock / fake to simplify testing, but if the code you are testing calls static methods, it is effectively “tightly coupled” to this static method.

+14
source

The answer to the question, in my opinion, is "Object Oriented, it seems, is all that TDD people think about."

Why? I dont know. Perhaps they are all Java programmers who have been infected with the disease, forcing everyone to rely on six layers of indirection, dependency injection, and interface adapters.

Java programmers seem to like to complicate things in order to "save time later."

I recommend applying some Agile rules to your TDD: if this does not cause a problem, then do not fix it. Do not follow the design.

In practice, I find that if static methods are well tested, then they will not cause errors in their calling.

If static methods execute quickly, then they don't need a layout.

If static methods work with materials from outside the program, you may need a layout. In this case, you will need to model many different types of function behavior.

If you need to mock a static method, remember that there are ways to do this outside of OO programming.

For example, you can write scripts to process the source code into a test form that calls your layout function. You can link different object files that have different versions of the function in test programs. You can use linker tricks to override a function definition (if it didn't work out nested). I'm sure there are a few more tricks that I have not listed here.

+3
source

Easy to check static method. The problem is that there is no way to isolate your other code from this static method when testing other code. The calling code is closely related to static code.

A reference to a static method cannot be mocked by many laughing frameworks and cannot be overridden.

If you have a class that makes many static calls, then to check it you need to configure the global state of the application for all these static calls, so maintenance becomes a nightmare. And if your test fails, then you do not know which bit of code caused the failure.

As it’s wrong, this is one of the reasons many developers think TDD is nonsense. They put in a huge maintenance effort for test results that only vaguely indicate what went wrong. If they only reduced the connection between their units of code, then the service would be trivial and specific test results.

+2
source

This advice is mostly true, but not always. My comments are not related to C ++.

  • tests for static methods (which are <power> pure / non-static functions): i.e. work with inputs to get a consistent result. for example Add below - will always give the same value, taking into account a specific set of inputs. no problem writing tests for them or code that calls such pure static methods.
  • tests for static methods that consume a static state : for example. GetAddCount () below. Calling it in several tests can give different meanings. Therefore, one test can potentially damage the execution of another test — tests must be independent. So, now we need to introduce the static state method reset, so that each test can start from scratch (for example, something like ResetCount ()).
  • Writing tests for code that accesses static methods , but does not have access to the dependencies of the source code: it again depends on the properties of the static methods themselves. However, if they are rude, you have a complex addiction. If the dependency is an object, then you can add the installer to the dependent type and set / introduce a fake object for your tests. When the dependency is static, you may need significant refactoring before you can perform tests reliably. (for example, add an object-specific relationship between people that delegates a static method. Now connect a fake average person for your tests).

Let's look at an example

public class MyStaticClass { static int __count = 0; public static int GetAddCount() { return ++__count; } public static int Add(int operand1, int operand2) { return operand1 + operand2; } // needed for testability internal static void ResetCount() { __count = 0; } } ... //test1 MyStaticClass.Add(2,3); // => 5 MyStaticClass.GetAddCount(); // => 1 // test2 MyStaticClass.Add(2,3); // => 5 //MyStaticClass.ResetCount(); // needed for tests MyStaticClass.GetAddCount(); // => unless Reset is done, it can differ from 1 
0
source

All Articles