last day (15 days later) » 

18:44
53
A: Is testable code better code?

gbjbaanbIn regard to the common definition of unit tests, I'd say no. I've seen simple code made convoluted because of the need to twist it to suit the testing framework (eg interfaces and IoC everywhere making things difficult to follow through layers of interface calls and data that should be obvious p...

"Given the choice between code that is easy to understand or code that is easy to unit test ..." I hate to choose, so I strive to have both. Not always possible, but more possible than many like to admit.
+1 for having the guts to come out and say it. A lot of times, making something "testable" requires you to turn simple, clear code inside out and make a horrendous mess of it.
@MasonWheeler cheers, I know its not fashionable but I dislike the cargo-cult attitude of unit testing we have today. A guy I worked with a while back was very proud of the 1500 tests he'd written for a rather simple service. Its almost like testing has become a bit of a game (like gathering SO points ;) ) and we end up with questions like this, getters tested, design patterns solely to assist the test tools, and when a language gains keywords to test stuff like private methods, you know people are playing with the new toy, and have stopped thinking what they are really trying to achieve.
Such comments should be taken with a grain of salt. Testable code should refer to non-trivial code in general. Turning simple, trivial code chunks inside out just to make them testable, that is just doing things the wrong way. Perhaps we should borrow a phrase made by Dijkstra ("usefully constructed") and say "testable, usefully constructed code" instead of simply saying "testable code". Good code is not defined by a single attributed, but by multiple ones that create a desired equilibrium of pros and cons.
because of the need to twist it to suit the testing framework -- this is not the framework's fault, it's typically a result of constraints of the language. Proper testing in Ruby and JS is actually pretty easy in comparison to the same in Java/C#.
18:44
@jcollum: I'm not sure you can blame the language for not fitting the testing framework. If a testing framework's testing philosophy requires twisting the language that the framework is written for, that sounds like a design flaw in the testing framework.
Kik
Kik
Post of the year.
@MichaelShaw yeah that all sounds right until you need to write tests against some legacy code that you can't modify -- then you realize it's a problem in the language; you go try to mock out the current date in C# and get back to me
Bob
Bob
@jcollum Actually... it looks very very easy given the right framework. Heck, that's an official MS-supported framework. And the example usage specifically addresses mocking DateTime.Now, almost as if it were waiting for your challenge :P
@Bob yes, however Fakes is only provided in VS Premium or Ultimate. It used to be called Pex/Moles and it used to be free. In other words, you need $$$ to get this functionality -- something that is provided for free in Javascript and Ruby. That doesn't strike you as a language limitation? It does to me.
I get sick of this attitude after having had to clean up after code where someone has said "this code is obvious" and the code has been deeply embedded in other code so they didn't bother to write tests for it, relying on the integration tests to catch any failures. And then it has failed spectacularly (and often embarrassingly so) on edge cases ... cases that had the code been structured correctly would have taken only a few minutes to write. And then someone needs to restructure the code to ensure it never happens again. Code that doesn't have unit tests is not maintainable code.
18:44
@MichaelAnderson: Just because some code exists that has no unit tests and is unmaintainable, doesn't mean that all code without unit tests is unmaintainable.
@MichaelShaw that statement is impossible to disprove. Still, it is also impossible to disprove the statement that if you have untestable code, you simply cannot prove that the code actually works as designed. If indeed it was designed. I find myself highly sympathetic to this post, though.
I don't really see how the attitude of a unit being a class rather than a method implies less granular. If I have a class that's some kind of simple storage with a void Add(object key, object value) method and object Get(object key) method, then trying to test those two methods as their own units in isolation of each other would be hard. Testing the whole class together as a single unit fits a lot better. But choosing between those two approaches seems like an orthogonal decision to choosing the level of granularity to test at.
@BenAaronson indeed. It just invites more granular classes, putting each service method in its own class rather than grouping them by functionality. So instead of having an OrderService, you get an AddOrderLineToOrderService, a CreateBillingInformationForOrderService, etc. etc. etc.
@BenAaronson its a feature of some test frameworks that will auto-generate stubs for you, each individual method becomes a test case. That's a problem IMHO, writing your own test cases based around the class prevents this kind of unthinking fill-in-the-blanks way of writing tests.
@EricKing Of course, by doing that, you still made a choice - you just chose a third option :D In the end, it's all about the costs. That's your final arbiter - does doing things this way actually save us money? Sadly, it's also extremely hard to judge; especially given that unit tests aren't a bullet-proof solution, obviously - unit tested code can still fail, even if all the tests are green.
18:44
@MichaelAnderson seems to me your problem is with the arrogant coder who writes bad code. I've been maintaining code that was written way before unit testing became such a hip thing to do and managed quite well - the trick to make code maintainable is primarily down to its organisation, clear separation of concerns is the key, not the tests. Now obviously clearly designed code is easy to test, so you're not far off, but I think you're confusing the symptom of testing with the cause of clear design. Many test tools we use today hinder that root goodness, that was my point.
@MichaelAnderson - Code that doesn't have unit tests is not maintainable code. That is a complete and utter horseshit. You're saying that all the words best programmers were writing unmaintainable code before the fad of unit testing came?
Let's keep it civil; this is not a clear-cut issue. Is it possible to write clear, maintainable code that is still tricky to test? Yes, of course. Is test-covered code harder to read than the untestable equivalent? Sometimes, yes, if the test framework makes you jump through some hoops, which some do. Does adding tests to code make it easier to maintain that code? That's beside the point of this question, but yes, in general it does. Is it possible to have tests that add nothing to maintainability? Yes, if you're bad at designing tests or you don't fully understand how and why we test.
@anaximander For code to be maintainable, you have to be able to make changes and be confident after a reasonable length of time that you haven't introduced bugs. I just don't see how anything can substitute for unit tests in giving you that confidence
@gbjbaanb MichaelAnderson specifically mentioned that the problem was failure to test for edge cases. Just writing good code doesn't magically vanish edge case considerations
@BenAaronson I agree in general - if you can't change code for fear of breaking something, it's not maintainable. Unit tests mitigate that by helping you spot how and why it's broken, but they're a means to an end, not a goal. If you're in some weird edge case scenario where the changes required to make your code testable also makes it unreadably complex, then perhaps you'd be better served by clearer code with less granular tests. In the vast majority of cases I'd expect that better code will also happen to be easier to test, but that doesn't mean that testable code is always better.
@BenAaronson but unit testing doesn't cater for edge cases either, each unit can work perfectly in isolation and yet fail to produce a working product, we all know that and have integration tests, but even those can fail to exercise a product sufficiently (eg under load or with certain environmental issues). In these cases, good code makes the difference in figuring out and fixing the issues.
18:44
@gbjbaanb I don't think anyone's disputing that well written code is necessary for maintainability, just whether or not it's sufficient. No testing method can give you absolute perfect confidence that you haven't missed an edge case, but for cases that exist at the unit level, it means the difference between a high level of confidence and almost 0 (which is what integration tests alone give). You can also reread the previous sentence and swap the words "unit" for "integration" when they occur, and that's true too.
@BenAaronson so no test is good enough, and that what is important is to structure your code well. Hence my original point that having to twist your code to suit some tool is a very bad thing. We need better tools so we can write good, clean, maintainable code that doesn't require all the artificial constraints they demand of us.
@gbjbaanb I've yet to see an example of a test tool forcing you to twist code into a less maintainable structure. Personally as a maintainer if a test tool has forced my predecessor not to litter her code with static dependencies, then that would make me cheer rather than cry.
The notion that developers who write unit tests do so because it is "hip" is a peculiar one. There are about a million things I'd rather do with my time. I write unit tests because in the long run they save time and pain.

  last day (15 days later) »