Wow
* easy to understand
* quick to write
* fast to run
Contrary to what I may have indicated in the past, I have actually written
products with tests, while the tests were valuable, they were generally:
* challenging to read
* hard to write
* slow to run
As a result, I have tended to write fewer tests than I should on projects.
If this thing works as advertised, I may begin to "sup" at the testing
"table" more often.
On Wed, Jul 2, 2008 at 3:41 PM, Martin Aspeli <[EMAIL PROTECTED]> wrote:
> Hi Maurits,
>
> I have not tried any code (also not from Dexterity), only read your
>> article. Some things are not clear to me.
>>
>> - At the end of the first mock example you say: "We must remember to put
>> the test case into replay mode, using self.replay()." Why? What does
>> that do?
>>
>
> Before you put the mock into replay mode, it's in "record" mode. All
> operations you do on it are essentially expectations. For example:
>
> mymock = self.mocker.mock()
> self.expect(mymock.foo()).result(True)
>
> Now, if I do
>
> mymock.foo()
>
> without putthing the mock in replay mode, it's basically just recording an
> expectation that foo will be called. In fact, the above could have been
> rewritten as:
>
> mymock = self.mocker.mock()
> mymock.foo()
> self.mocker.result(True)
>
> though I prefer the self.expect() chaining syntax as it's more compact.
>
> Only when the mock is put in replay mode will it actually exhibit the
> behaviour and check that it's being called in the expected way. You do that
> with
>
> self.replay()
>
> This is how most mock libraries work. You start off in record mode, doing
> operations on the object that "record" expectations about how it should be
> called. You then put it into "replay" mode and call the code under test
> (initialised to use the mock, obviously). The mock library then checks that
> recorded operations actually happen (in the way that they were recorded) and
> throws assertion errors if they're not. Finally, you do a verify + restore
> (implicit in the unit test) that ensures no steps were missed and unpatches
> anything patched for the test.
>
> - In the third mock example you say that we "set the expectation that
>> lookup_schema() should be called on it once", stressing the word
>> 'once'. Which part of the test code does that? From the paragraphs
>> after that I *guess* that whenever the code is this:
>>
>> self.expect(...).result(...)
>>
>> it implicitly means this:
>>
>> self.expect(...).result(...).count(1, 1)
>>
> >
>
>> Is that a correct guess?
>>
>
> Yes.
>
> If so, I think you should mention that
>> explicitly, perhaps already in the first mock example.
>>
>
> In record mode, the assumption is that if you record an action once, you
> meant for it to happen once. Let's say I have a mock and I expect it to be
> called twice, returning one thing the first time and something else the
> second time:
>
> magic_eight_ball = self.mocker.mock()
> self.expect(magic_eight_ball()).result("No")
> self.expect(magic_eight_ball()).result("Yes")
>
> BTW, if that is correct then I would find "count(0, None)" a more
>> logical default, so by default no restriction on the number of times
>> a mocked method is called.
>>
>
> Most mock libraries don't work like this. They fail when a method is called
> too many times (and will tell you so). I think it's (marginally) better to
> be explicit if you don't care how many times something's called. It's likely
> that if you expected something to be called, and it's called 0 times, then
> it's an error, and if it's called dozens of times, it's also an error.
>
> And a question: is there next to mock_utility also something like
>> mock_tool, so you could you this to mock for example the
>> portal_catalog? I guess something along these lines might work:
>>
>> from whereever import CatalogTool
>> catalog_mock = self.mocker.proxy(CatalogTool())
>> context_mock = self.mocker.mock()
>>
>> self.expect(context_mock.portal_catalog).result(catalog_mock).count(0,None)
>>
>
> No. There could be, but bear in mind that mock tests are not running in a
> PloneTestCase (which is why they're so quick) - at least not normally (no
> reason they couldn't be, but then you're really doing an integration test).
> As such, if your code calls getToolByName(), you'd probably do a replace()
> on this.
>
> A generic mock_tool() could look like this, though:
>
> from mocker import ANY
>
> class MockTestCase(...):
> ...
> getToolByName_mock = None
>
> def mock_tool(self, tool_mock, name, expected_context=ANY,
> min=1, max=None):
> mock = self.getToolByName_mock
> if mock is None:
> self.getToolByName_mock = mock = \
> self.mocker.replace('Products.CMFCore.utils.getToolByName')
> self.expect(mock(expected_context,
> name)).result(tool_mock).count(min, max)
>
> Untested and possibly refactorable of course.
>
> Martin
>
> --
> Author of `Professional Plone Development`, a book for developers who
> want to work with Plone. See http://martinaspeli.net/plone-book
>
>
> _______________________________________________
> Product-Developers mailing list
> [email protected]
> http://lists.plone.org/mailman/listinfo/product-developers
>
_______________________________________________
Product-Developers mailing list
[email protected]
http://lists.plone.org/mailman/listinfo/product-developers