|
But Shirley in almost all cases, once developed, one doesn't care what the results of a private method are - one only cares what the results of public methods are.
If a public method calls zero or more private methods to produce an outcome, changes to any of those private methods don't matter, as long as the results of the public method remain unchanged.
What's the point of testing a private method that is used by a public method? It just means the private method gets tested twice.
Although... if the private method accesses (e.g.) the database and so needs to be mocked, then it never gets tested - but then should one test such methods at all in a TDD environment (as it involves setting up and tearing down a whole database)...
** I'm not particularly arguing for one case or the other - more asking out of my poor understanding of TDD, which I'm not really practising in my current role.
PooperPig - Coming Soon
|
|
|
|
|
_Maxxx_ wrote: one only cares what the results of public methods are.
True, because you have faith that the private parts (no pun intended) are doing their job correctly.
_Maxxx_ wrote: If a public method calls zero or more private methods to produce an outcome, changes to any of those private methods don't matter, as long as the results of the public method remain unchanged.
OK, sure, there are public methods that need testing too, and yes, you can make everything public, but the point of private functions is to do, well, private stuff. So, if you have public functions that don't call any private functions, I would suggest that you delete those private functions as they are wasting space.
_Maxxx_ wrote: What's the point of testing a private method that is used by a public method? It just means the private method gets tested twice.
That's not what I said. A good unit test engine needs to provide the ability to test the private functions, through reflection. In all likelihood (and certainly my experience) the public functions aren't worth testing.
_Maxxx_ wrote: Although... if the private method accesses (e.g.) the database and so needs to be mocked, then it never gets tested - but then should one test such methods at all in a TDD environment (as it involves setting up and tearing down a whole database)...
A database interface is particularly annoying to test for the reason you stated. However, if you need to use a mocking framework to test functions that rely on the database, you've designed your code wrong. The DAL should be easily simulated by instantiating a simulation rather than some complicated mocking system. In other words, if you architect your code correctly, you don't need overly complex unit testing solutions.
I'm also not an advocate of TDD. Sometimes I write the code, walk it through the debugger, and I'm done. Othertimes, I write unit tests because I want regression testing for complicated stuff that might need bug fixes my test coverage doesn't handle. I actually never "write the test first." I find it a waste of time. I know a lot of people that get their jollies seeing little red indicators turn green when they write the implementation. Me, I think most of those tests are utterly pointless.
TDD should be used judiciously. I'll give you an example. I am in the middle of writing a SQL generator for CRUD operations on weird database architecture. I decided to first get some core behaviors implemented, like ridiculously simple queries, that I then wrote some tests for to vet out further. While I was writing the code, I made comments about "need to test this scenario" and "TODO: need to handle this condition". Those became good guidance for then writing other tests first that I knew would fail in the existing code, upon which I went back to the existing code and enhanced it (not fixed it) to handle those other conditions. I then repeated the process with other behaviors that I needed:
write a basic process
test it
expand the tests
revise the process
I find that that process works very well for me and keeps me focused on meaningful tests.
And no, I'm not testing unit level functions, I can do that perfectly fine by stepping through them in the debugger. In this case I'm testing the big honking function that glues everything together. However, if I were truly disciplined, I actually would be coding everything in nice small private functions and writing unit tests for those. As it is, there is a "TODO" on my big honking function that says "break this apart into smaller pieces" which I am disciplined enough to do next.
However, another thing that TDD doesn't really talk about is writing experimental code, and the idea of the tests is actually to prove or disprove that what I'm trying to do can be done and that my approach is solid.
Anyways, I'm rambling, but the point is, I see TDD misapplied because programmers don't understand the fundamentals of a good testing practice.
Marc
|
|
|
|
|
I see this as being another case of someone not using the idea of <practice> and saying it doesn't work properly.
(for <practice> you can insert anything from TDD to MVVM to LinqToSQL to whatever).
But I still don't get why you think you need to test individual private methods? Sure, when you are developing you might do bit of R&D in a private method - and you might even write some code just to test it - or run it through the debugger to make sure it's doing what you expect it to do. But the information in that method CANNOT get out without some public method accessing it (and by method I include property) - so it doesn't need a test.
Surely the idea of tests is that they can be run whenever a change is made and reassure you that you haven't broken anything.
Marc Clifton wrote: And no, I'm not testing unit level functions, I can do that perfectly fine by stepping through them in the debugger.
But what happens when another developer in 6 months changes something in one of these methods that then causes all hell to break loose? The hell breaking looses does not necessarily occur in the method he has changed - so even if he steps through his method in the debugger, nothing will appear strange, but that method may be used from hundreds of other places, each with different needs - and stepping through in debug mode just isn't practical in this case; even identifying every path would be a nightmare...
Bottom line, I think, is that if you are going to use TDD at all, you need to design your software in a way that enables its use for all public methods, and for every possible use of each; Now, when the tests run, you know nothing is broken.
Marc Clifton wrote: The DAL should be easily simulated by instantiating a simulation rather than some complicated mocking system.
Not sure I follow - are you saying that if your service layer returns an object via the database you should create a class that instantiates one of those objects with some test data in it for testing? If so, surely that is exactly what testing frameworks do - by faking up the method call and returning a test object? Or am I missing your meaning?
PooperPig - Coming Soon
|
|
|
|
|
it seems like you are testing the implementation more than the behavior!
making it hard to implement thing a different way!...
|
|
|
|
|
Super Lloyd wrote: it seems like you are testing the implementation more than the behavior!
Correct. Behavior relies on implementation.
Super Lloyd wrote: making it hard to implement thing a different way!...
Not necessarily. If I change the implementation of a function, it's behavior should still be the same -- given the same inputs, I get the same outputs as before the change.
When you refer to testing the implementation, yes, there is a close coupling between a test and its implementation -- it pretty much needs to be that way, it doesn't matter if you're testing private functions or public ones.
Marc
|
|
|
|
|
At least in case of .Net:
If you really want to keep some methods away from public but still want to test them with unit tests consider making them internal instead of private . You can then set an assembly attribute to make them visible to your test project (InternalsVisibleToAttribute[^])
Or if you really absolutely want to test private methods: Noone stops you from using reflection and doing just that.
|
|
|
|
|
Hmm.... grcchh... I have to disagree - not necessarily with the result, but with the reasoning.
Now there are a lot of assumptions going into how the public interface is implemented. Yet, at the general level, the core responsibility of a unit test is to verify observable behavior of a functional unit.
This seems pretty straightforward to me, since
- Other components relying on it will do so through the public interface.
- The public interface resembles more or less closely the specification of the functional unit.
- A significant element of the observable bahavior that requires testing is preserving invariants - something your privates usually don't do
So the question is not should we test public or private, but is testing the public interface sufficient?.
I can imagine quite some scenarios where this is not:
- You are not exposing sufficient state to test for invariants.
In some cases that's simply missing from the interface (e.g. a SetCapacity without GetCapacity ), but I concede there are cases where this state wouldn't need to be public except for tests. - Performance guarantees like "amortized O(1)" are hard to test for.
I've worked around this in some cases by e.g. exposing "cache stats" or "performance stats" in the public interface (which tend to end up in the final app diagnostic anyway). But again, I concede there's not always a reasonable solution. - You've built a complex interface ("the car") entirely of private elements ("the engine" etc.) that are not individually testable.
As much as I detest the very idea of Test Driven Design (*shudder*), I would concede that automated testability is a relevant stake in the architecture, so - unless there's unjustifiable burden on other stakes - "the engine" should be testable as well. - While having a public interface, the sub component is private in its entirety, thus the interface is not available form the outside for testing.
My own conclusion is: the public interface is the primary interface to be tested. If tests require access to privates, at least consider if the public interface is complete and/or a sub component should be isolated for testability. Then, remember my personal motto of "Test what is easy to test, you won't catch everything anyway". After that, there's little privates to be tested left, anyway, which is sufficiently rare to make test-only functionality accessable within the public signature.
|
|
|
|
|
I hate duck-typing and its typeless parameters and function returns.
I despise silent exits, not even a little whimper of "$foobar" not defined.
I loathe $this-> . What moron language designer required this construct?
I detest prefixing variables with "$", it harks back to the days of BASIC ass$="you are".
I piss on your brace style if ( condition ) {
Who came up with this POC language and why was (or is it still) all the rage? I understand WordPress uses PHP?
If you haven't guessed, I'm having to do some PHP programming.
[edit]Oh, and I would like to add to this rant the lack of any concept of OOD even though classes are supported. It's been a looong time since I've had to read through methods like sqlsrv_[whatever] and realize their not wrapped in a class. So guess what I did?
Which of course promotes non-OOD spaghetti code practices, which is what I'm fixing right now. It's a amazing to me how people can f**** up less than 500 lines of code into an untestable morass of garbage.
[/edit]
Marc
modified 6-Oct-14 16:15pm.
|
|
|
|
|
I think PHP has now been surpassed by JavaScript in most categories, especially the awards for the least maintainable code, most annoying syntax and greatest error potential. Only in the category 'Most Annoying Community' there are some close comptitors (Java and VB).
The language is JavaScript. that of Mordor, which I will not utter here
This is Javascript. If you put big wheels and a racing stripe on a golf cart, it's still a f***ing golf cart.
"I don't know, extraterrestrial?"
"You mean like from space?"
"No, from Canada."
|
|
|
|
|
You're having the same motive as I had, when I wrote Why Use ASP.NET for Web Development[^] but just a little bit more aggression.
Favourite line: Throw me to them wolves and close the gate up. I am afraid of what will happen to them wolves - Eminem
~! Firewall !~
|
|
|
|
|
Afzaal Ahmad Zeeshan wrote: You're having the same motive as I had,
I like your PHP example adding two integers.
Marc
|
|
|
|
|
Marc Clifton wrote: I like your PHP example adding two integers.
Loose types are perfect for the web though. His example is just his bias. I could give tons more examples where PHP is much much much more cleaner than C# when converting types, which a lot of programs have to deal with, especially if using more than one input or output stream (like the web).
Would I prefer a strong type in PHP? I would. Is it nearly as big a deal as people that never use PHP make it out to be? Not at all. In years of using PHP I've only had a handful of issues arise from loose types.
Jeremy Falcon
|
|
|
|
|
When you wrote "silent exits" I thought you were ranting about Ruby for a moment.
cheers
Chris Maunder
|
|
|
|
|
Chris Maunder wrote: When you wrote "silent exits" I thought you were ranting about Ruby for a moment.
Touche.
Marc
|
|
|
|
|
Aw, quit "Graus"ing about it...
Will Rogers never met me.
|
|
|
|
|
So now the poor man has his own verb?
The language is JavaScript. that of Mordor, which I will not utter here
This is Javascript. If you put big wheels and a racing stripe on a golf cart, it's still a f***ing golf cart.
"I don't know, extraterrestrial?"
"You mean like from space?"
"No, from Canada."
|
|
|
|
|
Jeremy Falcon
|
|
|
|
|
I realize this is just a good old fashioned rant, but most of your gripes have to do with not knowing the language man. Plain and simple. Now, PHP is not the most modern language in the world, gotta give you that, but it has a LOT of functionality and runs on a lot of platforms. I mean a lot. It's still pretty dang speedy too. In this little place called reality, that's more important than hating it because of using $ to denote a scalar variable.
But hey, totally awesome rant nonetheless.
I'd also stay away from Perl if you don't like PHP. Fair warning.
Jeremy Falcon
|
|
|
|
|
|
Yup, so I know it pretty well. It has some "wtf" things about it, but it's not nearly as bad as the people on CP that never use it make it out to seem. But in all fairness, it's not a modern language.
Jeremy Falcon
|
|
|
|
|
I thought so. So far you were the only one who defended it, I think.
I used to code a lot in Perl, so I am familiar with weird syntax, also. Although I absolutely hate working with Perl, it still is very powerful and is still a valid and relevant tool.
|
|
|
|
|
Slacker007 wrote: I used to code a lot in Perl, so I am familiar with weird syntax, also. Although I absolutely hate working with Perl, it still is very powerful and is still a valid and relevant tool.
Totally agree. Same thing with regex. It looks like someone took code and put it in a blender, and yet I'm still very glad we have it because of its flexibility when quickly writing searches in comparison to manually coding one.
Jeremy Falcon
|
|
|
|
|
Jeremy Falcon wrote: but it has a LOT of functionality and runs on a lot of platforms.
In that, I agree. There is a simple elegance to it, I just wish there was some tool out there that did a Lint or equivalent to find all my stupid mistakes, like passing in $foo and using it like $foos.
Jeremy Falcon wrote: because of using $ to denote a scalar variable.
Wait, I don't have to use the $? I thought it was intended to make it clear this isn't a function definition. Regardless, me noob.
As a lightweight scripting language, it looks like it carries a lot less baggage than other things I've seen.
Jeremy Falcon wrote: But hey, totally awesome rant nonetheless.
I aim to please.
Marc
|
|
|
|
|
Marc Clifton wrote: Wait, I don't have to use the $? I thought it was intended to make it clear this isn't a function definition.
The short answer is, you gotta use it.
Marc Clifton wrote: I just wish there was some tool out there that did a Lint or equivalent to find all my stupid mistakes, like passing in $foo and using it like $foos.
This is the biggest problem for the language, they're out there. But the only out-of-the-box solutions like you get with VS aren't free. Even still, there's some configuration that must take place.
Just the Unix-y way of life man. Microsoft excels at ease of use, Unix/Linux says piss off n00b unless you RTFM.
Jeremy Falcon
|
|
|
|
|
Jeremy Falcon wrote: Unix/Linux says piss off n00b unless you pound your brains into a bloody pulp R(ing)TFM, and don't catch the endless exceptions to the rules, because we never F'ing documented them for you! And if we did, we put them in some obscure location that is only findable after your exposed brain stem smashes through the screen, triggering an epileptic-like seizure that miraculously moves your fingers into an archaic 'man' command line sequence that infinite monkeys could never reproduce.
FTFY
|
|
|
|
|