
First of all, I'm sorry for my English. (And I'll appreciate it very much if someone will point to mistakes of any kind in the following text.) I attempted to analyze and structure comments, questions and ideas presented in the thread and I think I found one thing that can be a starting point for the discussion (despite the fact the discussion already started… away back). I've got a strong feeling (I've got it several years ago and had a number of evidences, including several in this thread) that there are (at least) two very different (if not opposite) points of view on mock objects… and it seems to me, the root of this divergence is even deeper and more general — understanding of TDD. So, I think I have to explain my point of view. (Telling "my" here I claim to be an author of all errors, misinterpretations and nonsenses I'll present. But all the good, reasonable and interesting things were invented by other (clever) people.) So, why and how did I dare to claim TDD is not really popular among Smalltalkers? Because I still believe tests can drive (nearly) all stages of development: not just coding, but also design and even analysis (at least to clarify and formalize results of analysis). But I rarely (if ever) see any artifacts (tests of the kind). Perhaps I'm wrong, but most of the tests I saw were more "acceptance" tests, perhaps even written afterwards. Once again: very likely I'm wrong (and I'll be glad to be, actually). Why is it important for me to use TDD? Because, as a bad programmer, I need a help. I have a lot of things I must think about during development (won't enumerate, we all know them), so I want a tool that helps me not to think too much — at least, at the points where it is possible at all. (If I misinterpret the word "driving" here, please let me know.) Thus, if I write a line of code that is not directly(!) driven by a test, I don't TDD. If I make some up-front design I'm not actually test-driven. Even, if I simply go few steps designing top-down without tests at a very small single stage of development, TDD is broken. If you think it is too extreme and strict — ok, let's talk about "seamless TDD" vs., say, "partial TDD". (Yes, I know about steps of variable size during TDD etc. But I still think it's a bit another thing. Let's judge a bit later…) So, considering an example by Colin Putney: | set | set := Set new. set add: 3. self assert: (set includes: 3). vs | set | mock := MockArray new: 5 mock expect: (Message selector: #at:put: arguments: #(4 3)). set := Set withArray: mock. set add: 3. Isn't it obvious mocking array here is an overkill and the first test is better? For sure it is. But why? Because there's actually no development in the 1st test. Otherwise, what is it for: #add: or #includes:? Which feature this test makes me to add to the system-under-test (the Set)? I must select, I must think, thus I'm not driven by the test. Consider also (slightly) another issue: here we have a ready-to-use inner collection for the Set. But if I have no yet? Isn't it a common and very frequent situation during development: I have to implement a (sub)system that comprises several objects working together? (I think I don't have to provide examples here to prove.) Which one should I implement first? I don't know, I have to explore. I must analyze the system, i.e. divide it into subcomponents, find the ones independent and start by implementing them first. But what is this process, I've just described? It's a top-down up-front design. Is it test-driven? Obviously, no. Do I have an alternative? Yes, I can use mocks. With Mocketry I could write: SetTests >> testStoresElementsInInnerCollection [:collection | set := Set withArray: collection. [set add: #element] should strictly satisfy: [collection add: #element]] runScenario Of course, this is a very early step of development, as I'll have to implement an efficient algorithm to check, if element exists in the set before adding it… And with mocks it is very likely I'll be driven to implement it as a pluggable object. Probably, this can make Set a bit more flexible, doesn't it? On the other hand, it can introduce unnecessary complexity. Apparently, this is a good example to explore it further… While I must admit technique of mock object is not a silver bullet, and must be used carefully… just as any other tool. So… Conclusion 1: Yes, mock objects is a specific tool for specific situations. But as for me, I meet these specific situation almost as frequently, as other, non-specific(?) circumstances. Conclusion 2: I think mocks should be used, first of all, to discover different aspects of functionality and distribute it among various objects. (Documentation, optimization, etc. goes later… if goes at all…) When I start to work on a new feature, I first try to write an acceptance test. But I never can implement it 'as is'. And I hate to leave it red or mark it as ignored (in any way). So I try to transform it into something I can implement easily and fast. And often this leads me to a test with mocks. This make me to divide complex functionality into smaller blocks and factor them out to collaborators. The trick is to make those objects to behave (one-by-one and altogether)… But that's another (and big) topic. -- Dennis Schetinin