last day (28 days later) » 

11:08 PM
32
A: Is static universally "evil" for unit testing and if so why does resharper recommend it?

Robert HarveyLooking 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 ...

 
@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.
@jk. Uh... Delegates are objects.
 
As a fan of using static methods I previously lost this argument to a TDD-oriented developer. Let's say you have a static helper method that does a simple task (in a completely stateless mannner). That method is used in 15 different places throughout other methods, it also has a bug causing every other method that uses it to fail their tests. The primary goal of TDD is to isolate code for testing without side-effects. A static method that gets called inside another method will always be a side effect.
 
@EvanPlaice: Your argument is not compelling; non-static methods can also fail in multiple places. The difference being, non-static methods can often modify local object state, an undesirable quality which is not true of static methods.
 
(Cont) Of course, you could always test static methods before instance methods to fix the issue, but what about static methods that call other static methods. Forcing a constraint that tests must be run in a specific order is a serious code smell in the world of TDD. Theoretically, static methods are terrible for testing but in practice people very rarely ever provide 100% test coverage anyway so YMMV.
 
@EvanPlaice The ordering of tests is not necessary when testing static methods, even if they call other static methods.
 
11:08 PM
@RobertHarvey The point is, non-static methods can be written in a way where they're completely isolated and free of side-effects. The benefit of static methods is that they're globally accessible. I'm not saying that's a bad thing but from a testing standpoint, it's a definite weakness that needs to be taken into consideration.
 
@EvanPlaice What weakness? The visibility of static methods has nothing to do with their safety. In practice, static methods are sequestered behind a namespace or static class anyway. But even if they weren't, they don't hold any state (if they are written properly), so it doesn't matter anyway. A static method's influence disappears completely once it returns.
You are an advocate of the Functional Programming paradigm, yes?
 
I'm not an advocate of anything but I do like functional programming and static classes.
I'm not saying static classes are inherently bad, they just have some weaknesses from a pure TDD standpoint
Here's an example:
Lets say you have a class that's designed to fetch the weather. In your application it would be forked off into a ton of instances to get the weather from all over the world. To test it, only one instance is spooled up and it's fed simulated data to mock a controlled environment.
 
Then there's a static helper class that handles conversions.
The weather class gets extended to fetch other types of data, tests are added over time, and the conversions static class gets updated along the same lines.
Over time a bunch of data retrieval classes (and methods) accumulate, many of which make calls to the conversion method static methods.
Everything has a test, both static and instance. Then, one day a newb dev walks in and decides he's going to 'improve' the conversion tests.
All of a sudden tests start failing all over the place.
 
Alright.
 
11:16 PM
When, in fact, it was only one bug that caused the problem.
Because each instance class was referencing the same static method, every one that called it was affected and subsequently failed.
 
You can break a non-static method in exactly the same way.
The only difference between a static method and a non-static method is that the static method can refer to local state being held in an object.
 
But it's actually possible to isolate non-static methods because you just fire up a new instance before each test.
 
You're using the same code. But each object holds its own copy of local variables.
OK. Here's my example.
Exactly the same as yours, except...
 
But each instance has it's own copy of it's internal data, free of side-effects
 
Static methods don't have side effects at all, if they're written properly.
 
11:19 PM
But instance methods that call static methods do.
 
Because the static method itself is an inherent side-effect.
 
If an error happens in the static method definition, it affects all other methods that call it. That's the classic definition of a side effect.
 
No, that's an effect, really :)
The same problem can happen with non-static methods.
 
11:21 PM
Tests are like science experiments. They should be done in a completely controlled environment.
 
Right. The controlled environment with a static method...
 
I don't disagree that it 'can' happen. It's just physically possible to code things in a way that it doesn't.
 
is that it only operates on what you pass into it
and it only affects what it returns.
 
I understand. But the problem isn't with the static method. It's in the other methods that call that static method.
 
There are no side-effects, because nothing is affected outside that call-return arrangement.
Same thing. They only operate on what they are passed. But there's an important difference.
If the methods are written properly...
they don't mutate what you pass into them. Instead, they return a new object.
That's not always true of instance methods.
 
11:24 PM
But instance methods don't affect other instance methods when they mutate their internal state
 
They do if those other methods are dependent on that internal state.
If those other methods don't depend on that internal state, guess what you have?
static methods.
In a conventional unit test with a non-static method and an object, it's not uncommon to provide elaborate mocking mechanisms to isolate all of the method's dependencies, yes?
 
That's why you write the test so they're not dependent on external state. Everything a test contains should start fresh. All instances used internally are instantiated from scratch.
The point being, instance methods can be written in a manner that they contain no side effects. Static methods can not.
From a purely TDD perspective, the TDD crowd makes a good point.
Personally, I say screw them and take the risk because static methods are too useful to ignore.
 
It sounds like what you consider a side effect is different than what I consider a side-effect.
If I have an object, and that object has a member variable foo
and I call a non-static method that mutates foo
that's a side-effect
because some other method that depends on foo
will have different behavior
because of the mutation.
If I call a static method that accepts an object and a value, and returns a copy of that object with its foo property set to something new,
 
Should people make the effort to make static methods stateless? Of course. Global state sucks and is difficult/impossible to test without side-effects.
 
I've accomplished the same thing, except that "some other method" I don't care about at all
@EvanPlaice That's all I
'm saying.
If you write all of your static methods so that they don't hold state
They're absolutely safe, from a TDD perspective.
In fact, they're better from a TDD perspective, because you don't have to mock anything.
 
11:33 PM
Static methods themselves aren't bad as long as they're checked along with everything else. Personally, I find it trivial to identify a failed static method test even when it cascades out and causes other tests to fail. That's what debuggers and stepping into code were designed for.
 
The TDD'ers are really missing the boat on this one.
Presumably, your static method is also covered by unit tests, yes?
Why would those tests be any different just because you're not newing up an object?
 
For the TDD purists, static methods will always be considered a side-effect. They have a valid point if you want to argue semantics. For me personally, it just gives me a good reason not to be a TDD purist.
 
They don't understand what a side-effect is, then. :)
Side-effects are all about mutating something that doesn't belong to you.
A properly written static method will never do this. It will only operate on whatever it is passed.
This is why Singletons are so often despised as a software pattern. A Singleton is really just a bunch of "static" state wrapped up in a real object to give it an air of legitimacy. But global state is global state; you might as well just have a bunch of static variables.
 

  last day (28 days later) »