|
From: Tim M. <tim...@po...> - 2002-08-26 23:23:45
|
It occurred to me that it would be useful to share this message with everyone in this group - as it fills in some history and thoughts. Tim ------ Hi Russ - You ask some good questions! We've been working with a few authors to clarify some of this (Steve is in fact working on a book on the subject). From a purist point of view I would say all 3 properties must be present. However it might be useful to fill in some background for you - we didn't just magically invent mock objects. Starting out with property 1, we found we had tests with lots of "getters" on them - all doing assertEquals on some property or another. We wanted to refactor them (to avoid duplication in our tests) and had to choose between putting them in some test superclass or putting them into the mock (although by our definition it was still a stub at that point). Moving them into the mock felt cleaner (it has a more OO feel to it, doesn't restrict you to test hierarchies and I'm not a big fan of inheritance anyway). So if you remove property 3, you will end up with lots of tests all having the same assertions (in my experience anyway) and the danger that you missed an important assertion as well. In the early days we were quite strict on asserting every attribute - however after lots of usage we found that just asserting on those attributes that you had set expectations on was a better approach. If you are too strict your tests become a bit too complicated. In this respect the much overlooked Expectation objects help you - they take care of this policy automatically. (again this was all based on our experience of writing lots of tests) The previous paragraph now hints at property 2 - you need to know what to assert on for your tests. In fact from a readability point of view - specifying preconditions makes your test much more readable. It clearly specifies that intent of the test. Having done this work - our experience was that Fail fast came for free. When you are debugging your code, I would say that fail fast is a god send - it gives you a way to imediately pop up a debugger exactly when the problem occured - and with modern IDE's (eclipse, visual age) you can even fix the problem and keep running. Steve often cites an example of a financial product he was working on while we were still discovering mock objects. They didn't have fail fast - and so had complicated calculation tests that just had a "fail" message, with no way of working out which of the stages of calculations had gone wrong. Having said all of this - the Expectation objects do have a failLate flag - which can be useful for "collection" style attributes where it can be clearer to see the full collection of values at the end of the test (to compare it with the expected list). I havent used this flag much - but it did crop up once in our production code. (The topic of failing with useful error messages is one which I covered in my XP2002 poster - A plea for assertEquals - there are too many bad test examples out there). I don't understand your point about "If the TestHelper isn't going to be used repeatedly by the Class". Setting an expection on a Mock gives great clarity. setExpectedDeleteRecord(1234) is a single interation with database type object - but it would make a test very clear, and the failure message would be extrememly useful. The test might bet be further enhanced with setExpectedAddRecordCalls(0) to ensure that no adds happen in this test as well (this is a patter I often see). I also don't understand the point "If different tests have distinct postconditions"? I think I may have covered this above - by setting expectations on a mock you are effectively doing this. Actually we don't really do postconditions in the sense you are hinting at - in that I don't think I've written a verify that checks the state of an object to make sure it matches a known condition. Of course you could do - and in this case to stay general you would probably need to factor out some object to hold all the states that you could check against (a different sort of expectation object I guess, an ExpectationPostCondition?). However - you don't normally need this becuase we are monitoring all the interactions coming in and can "fail fast". Having said this - one topic we've never properly addressed is message ordering - so an ExpectationPostCondition could be used for this kind of thing... I quite like that now I think about it. Hope this helps. And yes, if I was in the are, I would love to drop by. The same applies to any of you guys if you are in London, get in touch or stop the the ExtremeTuesdayClub and have a beer. Tim -----Original Message----- From: Russ Rufer [mailto:ru...@pe...] Sent: 23 August 2002 15:13 To: tim...@po...; st...@m3...; ph...@po... Subject: Defining Mock Object Hi, I lead the Silicon Valley Patterns Group, a technical study group in California. We studied your Endo-Testing paper (and realted papers) over the last two weeks, and we would really appreciate if you could help us with some clarification. The Endo-Testing paper never strictly defines what must be satisfied to justify using the term Mock Object. Crawling through the MockObject, Shunt, Stub, etc. pages on Wiki only add to the confusion. There seem to be three key ingredients: (I'll use the name TestHelper to avoid conflicting with definitions I'm trying to understand) 1: Provide an implementation of a TestHelper that your Class Under Test relies upon. A simple implementation of the interface that contains minimal code required to interact with the Class Under Test for testing. 2: Fast Fail. As soon as the Class Under Test attempts to interact with your TestHelper in an eroneous way, the TestHelper fails immediately, rather than hiding the problem until the test is over. 3: A verify() method on TestHelper that the test calls to check postconditions. Clearly (1) is essential. How about (2) and (3)? Would you use the term Mock Object if either of these were missing? E.g. If the TestHelper isn't going to be used repeatedly by the Class Under Test, failing fast (2) may not benefit your understanding of the failure. E.g. If different tests have distinct postconditions, the tests may be simpler if you just extend the TestHelper with getters not on the original interface. In this case a uniform verify() method might just be redundant--possibly empty. Also, are there any other key elements to Mock Object that you would want to include? Thanks for any light you can shed on this for us. BTW, if any of you find yourselves travelling to the Silicon Valley (or the San Fransico Bay Area) you might enjoy joining a meeting of the Silicon Valley Patterns Group. Or it might just be fun to meet for coffee or dinner while you're in the area. If so, please feel free to drop me a line. - Russ Rufer Silicon Valley Patterns Group --- Incoming mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.381 / Virus Database: 214 - Release Date: 02/08/2002 --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.381 / Virus Database: 214 - Release Date: 02/08/2002 --- Outgoing mail is certified Virus Free. Checked by AVG anti-virus system (http://www.grisoft.com). Version: 6.0.381 / Virus Database: 214 - Release Date: 02/08/2002 |