93

I have found that there are only 3 ways to unit test (mock/stub) dependencies that are static in C#.NET:

Given that two of these are not free and one has not hit release 1.0, mocking static stuff is not too easy.

Does that make static methods and such "evil" (in the unit testing sense)? And if so, why does resharper want me to make anything that can be static, static? (Assuming resharper is not also "evil".)

Clarification: I am talking about the scenario when you want to unit test a method and that method calls a static method in a different unit/class. By most definitions of unit testing, if you just let the method under test call the static method in the other unit/class then you are not unit testing, you are integration testing. (Useful, but not a unit test.)

14
  • 3
    TheLQ: You can. I believe he is talking about not being able to test static methods because much of the time it touches static variables. Thus changing the state after and between test.
    – user2528
    Commented Sep 21, 2010 at 2:44
  • 26
    Personally I think you are taking definition of "unit" too far. "Unit" should be "smallest unit that makes sense to test in isolation". That may be a method, it may be more than that. If the static method has no state and well tested then having a second unit test call it is (IMO) not an issue.
    – mlk
    Commented Nov 10, 2010 at 11:46
  • 10
    "Personally I think you are taking definition of "unit" too far." No, its just that he's going with standard usage and you're making up your own definition.
    – user29776
    Commented Aug 15, 2011 at 14:26
  • 7
    "why does resharper want me to make anything that can be static, static?" Resharper doesn't want you to do anything. It is merely making you aware that the modification is possible and maybe desirable from a code analysis POV. Resharper is not a replacement for your own judgement! Commented Feb 1, 2012 at 12:39
  • 4
    @acidzombie24. Regular methods can modify static state too so they would be just as "bad" as static methods. The fact they can also modify state with a shorter life cycle makes them even more dangerous yet. (I'm not in favor of static methods, but the point about state modification is a blow to regular methods too, even more so)
    – mike30
    Commented May 22, 2013 at 13:04

11 Answers 11

120

Looking at the other answers here, I think there might be some confusion between static methods that hold static state or cause side-effects (which sounds to me like a really bad idea), and static methods that merely return a value.

Static methods which hold no state and cause no side effects should be easily unit testable. In fact, I consider such methods a "poor-man's" form of functional programming; you hand the method an object or value, and it returns an object or value. Nothing more. I don't see how such methods would negatively affect unit testing at all.

24
  • 50
    The static method is unit testable, but what about the methods that call the static method? If the callers are in another class then they have a dependency that needs to be decoupled to do a unit test.
    – Vaccano
    Commented Sep 21, 2010 at 15:51
  • 24
    @Vaccano: But if you write static methods that do not hold state and have no side effects, they are more or less functionally equivalent to a stub anyway. Commented Sep 21, 2010 at 18:41
  • 23
    Simple ones maybe. But more complex ones can start throwing exceptions and having outputs that are not expected (and should be caught in the unit test for the static method, not in the unit test for the caller of the static method), or at least that is what I have been lead to believe in the literature I have read.
    – Vaccano
    Commented Sep 21, 2010 at 19:53
  • 23
    @Vaccano: A static method that has outputs or random exceptions has side-effects. Commented Dec 11, 2011 at 3:55
  • 11
    @TikhonJelvis Robert was talking about outputs; and "random" exceptions shouldn't be a side effect, they are essentially a form of output. The point is, whenever you test a method that calls the static method, you are wrapping that method and all permutations of its potential output, and cannot test your method in isolation.
    – Nicole
    Commented Aug 16, 2012 at 23:04
31

You seem to be confusing static data and static methods. Resharper, if I remember correctly, recommends making private methods within a class static if they can be made so - I believe this yields a small performance benefit. It doesn't recommend making "anything that can be" static!

There is nothing wrong with static methods and they are easy to test (so long as they don't change any static data). For instance, think of a Maths library, which is good candidate for a static class with static methods. If you have a (contrived) method like this:

public static long Square(int x)
{
    return x * x;
}

then this is eminently testable and has no side effects. You just check that when you pass in, say, 20 you get back 400. No problem.

11
  • 5
    What happens when you have another class that calls this static method? Seems simple in this case, but it is a dependency that cannot be isolated except with one of the three tools listed above. If you do not isolate it then you are not "unit testing" you are "integration testing" (because you are testing how well your different units "integrate" together.
    – Vaccano
    Commented Sep 21, 2010 at 15:54
  • 4
    Nothing happens. Why would it? The .NET framework is full of static methods. Are you saying you can't use these in any methods you want to unit test, either?
    – Dan Diplo
    Commented Sep 21, 2010 at 16:01
  • 3
    Well, if your code is at the production level/quality of the .NET Framework then sure, go ahead. But the whole point of unit testing is the test the unit, in isolation. If you are also calling methods in other units (be they static or otherwise) then you are now testing your unit plus its dependencies. I am not saying it is not a useful test, but not a "unit test" by most definitions. (Because you are now testing your unit-under-test and the unit that has the static method).
    – Vaccano
    Commented Sep 21, 2010 at 16:23
  • 10
    Presumably you (or others) have already tested the static method and shown that it works (at least as expected) before writing too much more code around it. If something breaks in the part you test next, that's where you should look first, not in the stuff you've already tested.
    – cHao
    Commented Sep 21, 2010 at 19:03
  • 7
    @Vaccano So how do Microsoft test the .NET Framework, then, eh? Many of the classes in the Framework reference static methods in other classes (such as System.Math) not to mention the abundance of static factory methods etc. Plus you'd never be able use any extension methods etc. The fact is, simple functions like this are fundamental to modern languages. You can test these in isolation (since they will generally be deterministic) and then use them in your classes without worry. It is not a problem!
    – Dan Diplo
    Commented Sep 21, 2010 at 19:06
20

If the real question here is "How do I test this code?":

public class MyClass
{
   public void MethodToTest()
   {
       //... do something
       MyStaticClass.StaticMethod();
       //...more
   }
}

Then, just refactor the code and inject as usual the call to the static class like this:

public class MyClass
{
   private readonly IExecutor _externalExecutor;
   public MyClass(_IExecutor executor)
   {
       _exeternalExecutor = executor;
   }

   public void MethodToTest()
   {
       //... do something
       _exetrnalExecutor.DoWork();
       //...more
   }
}

public class MyStaticClassExecutor : IExecutor
{
    public void DoWork()
    {
        MyStaticClass.StaticMethod();
    }
}
3
  • 11
    Fortunately we also have questions regarding code readability and KISS on SO too :)
    – gbjbaanb
    Commented Nov 15, 2011 at 18:42
  • would a delegate not be easier and do the same thing?
    – jk.
    Commented Nov 29, 2012 at 17:56
  • @jk could be, but its hard to use IoC container then.
    – Sunny
    Commented Nov 29, 2012 at 21:11
17

Statics aren't necessarily evil, but they can limit your options when it comes to unit-testing with fakes/mocks/stubs.

There are two general approaches to mocking.

The first one (traditional - implemented by RhinoMocks, Moq, NMock2; manual mocks and stubs are in this camp, too) relies on test seams and dependency injection. Suppose you're unit-testing some static code and it has dependencies. What happens often in the code designed this way is that statics create their own dependencies, inverting dependency inversion. You soon discover that you can't inject mocked interfaces into code under test that is designed this way.

The second one (mock anything - implemented by TypeMock, JustMock and Moles) relies on .NET's Profiling API. It can intercept any of your CIL instructions and replace a chunk of your code with a fake. This allows TypeMock and other products in this camp to mock anything: statics, sealed classes, private methods - things not designed to be testable.

There's an ongoing debate between two schools of thought. One says, follow SOLID principles and design for testability (that often includes going easy on statics). The other one says, buy TypeMock and don't worry.

14

Check this out: "Static Methods are Death to Testability". Short summary of the argument:

To unit test you need to take a small piece of your code, rewire its dependencies and test it in isolation. This is hard with static methods, not only in the case they access global state but even if they just call other static methods.

7
  • 35
    I don't keep global state or cause side-effects in my static methods, so this argument seems irrelevant to me. The article you linked makes a slippery slope argument that has no basis if static methods are confined to simple procedural code, acting in a "generic" way (like math functions). Commented Sep 21, 2010 at 14:53
  • 4
    @Robert Harvey - how do you unit test a method that uses a static method from another class (ie it has a dependency on a static method). If you just let it call it then you are not "unit testing" you are "integration testing"
    – Vaccano
    Commented Sep 21, 2010 at 15:48
  • 10
    Don't just read the blog article, read the many comments that disagree with it. A blog is just an opinion, not a fact.
    – Dan Diplo
    Commented Sep 21, 2010 at 16:10
  • 8
    @Vaccano: A static method with no side-effects or external state is functionally equivalent to a value. Knowing that, it's no different than unit testing a method that creates an integer. This is one of the key insights that functional programming gives us. Commented Nov 29, 2012 at 17:59
  • 3
    Barring embedded systems work or an app whose bugs have potential to create international incidents, IMO, when "testability" drives architecture, you had it twisted before you adopted test-every-last-corner-methodologies in the first place. Also I'm tired of XP's version of everything dominating every conversation. XP is not an authority, it is an industry. Here's the original, sensible definition of unit testing: python.net/crew/tbryan/UnitTestTalk/slide2.html Commented May 21, 2013 at 20:35
6

The simple truth rarely acknowledged is that if a class contains a compiler-visible dependency on another class, it cannot be tested in isolation from that class. You can fake up something that looks like a test, and will appear on a report as if it was a test.

But it will not have the key defining properties of a test; failing when things are wrong, passing when they are right.

This applies to any static calls, constructor calls, and any reference to methods or fields not inherited from a base class or interface. If the class name appears in the code, it is a compiler-visible dependency, and you can't validly test without it. Any smaller chunk simply is not a valid testable unit. Any attempt to treat it as if it were will have results no more meaningful than writing a little utility to emit the XML used by your test framework to say 'test passed'.

Given that, there are three options:

  1. define unit testing to be testing of the unit composed of a class and it's hard-coded dependencies. This works, providing you avoid circular dependencies.

  2. never create compile-time dependencies between classes you are responsible for testing. This works, providing you don't mind the resulting code style.

  3. don't unit test, integration test instead. Which works, providing it doesn't conflict with something else you need to use the term integration testing for.

2
  • 3
    There is nothing that says that a unit test is a test of a single class. It's a test of a single unit. The defining properties of unit tests are that they are fast, repeatable and independent. Referencing Math.Pi in a method does not make it an integration test by any reasonable definition.
    – sara
    Commented Jun 2, 2016 at 12:01
  • i.e. option 1. I agree that's the best approach, but it can be useful to know other people use the terms differently (reasonably or not).
    – soru
    Commented Jun 2, 2016 at 14:57
4

There's no two ways about it. ReSharper's suggestions and several useful features of C# would not be used as often if you were writing isolated atomic unit tests for all your code.

For instance, if you have a static method and you need to stub it out, you can't unless you use a profile based isolation framework. A call-compatible workaround is to change the top of the method to use lambda notation. For example:

BEFORE:

    public static DBConnection ConnectToDB( string dbName, string connectionInfo ) {
    }

AFTER:

    public static Func<string, string, DBConnection> ConnectToDB (dbName, connectionInfo ) {
    };

The two are call-compatible. Callers don't have to change. The body of the function remains the same.

Then in your Unit-Test code, you can stub this call like so (assuming it's in a class called Database) :

        Database.ConnectToDB = (dbName, connectionInfo) => { return null|whatever; }

Be careful to replace it with the original value after you're done. You can do that via a try/finally or, in your unit-test clean up, the one that gets called after every test, write code such as this:

    [TestCleanup]
    public void Cleanup()
    {
        typeof(Database).TypeInitializer.Invoke(null, null);
    }

which will re-invoke the static initializer of your class.

Lambda Funcs are not as rich in support as regular static methods, so this approach has the following undesirable side-effects:

  1. If the static method was an extension method, you have to change it to a non-extension method first. Resharper can do this for you automatically.
  2. If any of the data types of the static methods are an embedded-interop assembly, such as for Office, you have to wrap the method, wrap the type or change it to type 'object'.
  3. You can no longer use Resharper's change-signature refactoring tool.

But let's say you avoid statics altogether, and you convert this to an instance method. It's still not mockable unless the method is either virtual or implemented as part of an interface.

So in reality, anyone who suggests the remedy to stubbing static methods is to make them instance methods, they would also be against instance methods that are not virtual or part of an interface.

So why does C# have static methods? Why does it allow for non-virtual instance methods?

If you use either of these "Features", then you simply cannot create isolated methods.

So when do you use them?

Use them for any code that you don't expect anyone to ever want to stub out. Some examples: the Format() method of the String class the WriteLine() method of the Console class the Cosh() method of the Math class

And one more thing.. Most people won't care about this, but if you can about the performance of an indirect call, that's another reason to avoid instance methods. There are cases when it's a performance hit. That's why non-virtual methods exist in the first place.

3
  1. I believe it's partly because static methods are "faster" to call than instance methods. (In quotes because this smells of micro optimization) see http://dotnetperls.com/static-method
  2. It's telling you that it doesn't need state, therefore could be called from anywhere, removing the instatiation overhead if that's the only thing someone needs.
  3. If I want to mock it, then I think it's generally the practice that it's declared on an interface.
  4. If it's declared on an interface then R# won't suggest you make it static.
  5. If it's declared virtual, then R# won't suggest you make it static either.
  6. Holding state (fields) statically is something that should always be considered carefully. Static state and threads mix like lithium and water.

R# isn't the only tool that will make this suggestion. FxCop/MS Code Analysis will also do the same.

I would generally say that if the method is static, generally it should be testable as is as well. That brings some design consideration and probably more discussion than I have in my fingers right now, so patiently awaiting the down votes and comments... ;)

2
  • Can you declare a static method/object on an interface? (I do not think so). Ether way, I am referring to when your static method is called by the method under test. If the caller is in a different unit then the static method needs to be isolated. This is very hard to do with out one of the three tools listed above.
    – Vaccano
    Commented Sep 21, 2010 at 15:56
  • 1
    No you cannot declare static on an interface. It would be meaningless.
    – MIA
    Commented Sep 21, 2010 at 17:24
3

I see that after long time no one has yet stated a really simple fact. If resharper tells me that I can make a method static, it means a huge thing to me, I can hear his voice tell me: "hey, you, these pieces of logic are not current class's RESPONSIBILITY to handle, so it should stay out in some helper class or something".

3
  • 3
    I disagree. Most of the time when Resharper says I can make something static it's a little bit of code that was common to two or more methods in the class and thus I extracted it out to it's own procedure. Moving that to a helper would be meaningless complexity. Commented Nov 30, 2012 at 3:21
  • 2
    I can see your point only if the domain is very simple and it is not suitable for future modification. Differently, what you call "meaningless complexity" it's good and human-readable design to me. Having an helper class with simple and clear reason to exists is in some way the "mantra" of SoC and Single Responsibility principles. In addition, considering that this new class becomes a dependency for the main one, it has to expose some public members, and as a natural consequence it becomes testable in isolation and easy to mock when acts as a dependency.
    – g1ga
    Commented Nov 30, 2012 at 10:30
  • 1
    Not relevant to the question. Commented Mar 12, 2014 at 22:28
2

If the static method is called from inside other method, it is not possible to prevent or substitute such a call. This means, these two methods make a single Unit; Unit test of any kind tests them both.

And if this static method talks to Internet, connects databases, shows GUI popups or otherwise converts the Unit test into complete mess, it just does without any easy work around. A method that calls such the static method is not testable without refactoring, even if it has lots of purely computational code that would highly benefit from being unit tested.

0

I believe that Resharper is giving you guidence and apply the coding guidelines it has been setup with. When I have used Resharper and it has told me that a method should be static it is bound to be on a private method that does not act on any instance variables.

Now as for testablity this scenario shouldn't be an issue as you shouldn't test private methods anyway.

As for the testability of static methods that are public then unit testing does become hard when static methods touch static state. Personally I would keep this to a minimum and use static methods as pure functions as much as possible where any dependencies are passed into the method which can be controlled via a test fixture. However this is a design decision.

2
  • I am referring to when you have a method under test (not static) that calls a static method in another class. That dependency can only be isolated with one the three tools listed above. If you do not isolate it then you are integration testing, not unit testing.
    – Vaccano
    Commented Sep 21, 2010 at 15:52
  • Accessing instance variables inherently means it can't be static. The only state a static method can possibly have is class variables and the only reason that should happen is if you're dealing with a singleton and thus don't have a choice. Commented Nov 30, 2012 at 3:25

Not the answer you're looking for? Browse other questions tagged or ask your own question.