Keyboard Shortcuts
Likes
- Testdrivendevelopment
- Messages
Search
Re: [TDD] Single assert / Single mock rule in practice
P.S. in the first sentence of that second paragraph I should have said you stub the method and assert something about the SUT, only. In other words: For a query: Arrange: stub the query and pass the stub to the object under test
Act: call the method on the object under test that will cause the stubbed method to be queried Assert: assert something about the object under test that should only be true if the stubbed method returns correctly
For a command: Arrange: create a mock and pass it to the object under test * Act: call the method on the object under test that will cause the method on the mock to be called
Assert: verify that the mock was called correctly which should only be true if the object under test did what we expected * depending on the framework you may also have to specify how the mock is expected to be called before you call it.?
On Wed, Jan 15, 2014 at 3:20 PM, Adam Sroka <adam.sroka@...> wrote:
|
Re: [TDD] Single assert / Single mock rule in practice
Are you familiar with Command Query Separation (CQS)? I've always found that the most coherent and useful way to explain why you would choose a mock or a stub. The most interesting thing about a method is either what it returns or, in the case where you don't care what it returns, whether it was called with the correct semantics, not both.? So, if the SUT cares about the value that a method returns then you stub that method, only. If the SUT doesn't care about the value a method returns then you use a mock and verify the call has the expected semantics, only.?
Does that help?? On Tue, Jan 14, 2014 at 6:37 AM, Mateusz ?oskot <mateusz@...> wrote:
|
Re: [TDD] Re: Single assert / Single mock rule in practice
On Wed, Jan 15, 2014 at 12:56 PM, Mateusz ?oskot <mateusz@...> wrote:
It gets easier over time if you practice merciless refactoring. The problem is that most programmers don't. They change stuff when it is obvious and makes their lives immediately easier and defer it otherwise. Then it turns into a mess and they no longer know how to fix it easily.?
If you can see that you need to query internals to know whether something works or not that is a smell. If you try to fix it right then it is likely to be easier than if you wait. If you try to fix it and make it worse then try again. That is what version control was invented for (precisely.)?
If you need help understanding when and why to change stuff I recommend the eLearning product from Industrial Logic.? When and whether to use mocks is more a matter of style than anything else, and philosophical debates about it are mostly a waste of time.?
?
I was responding more to the wording "used deep in implementation" than the code in your example. However, just because it is a direct collaborator doesn't mean you are out of the water. Tight coupling between the SUT and a direct dependency is a smell (Inappropriate Intimacy, most likely, though it could be a couple other things too.)?
|
Re: [TDD] Re: Single assert / Single mock rule in practice
Mateusz ?oskot
On 15 January 2014 04:41, Adam Sroka <adam.sroka@...> wrote:
Yes, that is waht a general theory of (unit) testing says, but...devil's in the detail like classicists vs mockists ()
I mean, lots of things about unit teststing makes a perfect common sense and is obvious... from high altitude, but practice seems to be much more complex.
I believe that the fake xdep.get_item() from my example is a direct collaborator, isn't it? (let's ignore the fact get_item() is Python free function, not an object of class, it is irrelevant for this discussion).
? In my example, I think I don't do anything different than Roy Osherove [1] in faking his ILogger as mockLog object and veryfying mockLog.Expect("Write", "ya|"), am I?
[1] ?
Right, that is a very good question to remember/consider.
Yes, sounds sensible, if not obvious. Best regards, --? Mateusz ??oskot, |
Re: [TDD] Re: Single assert / Single mock rule in practice
Keith Ray
¿ªÔÆÌåÓýSometimes I have test-driven a class, and then I can refactor the "private parts" of the class until it is almost entirely different than the original code, but the tests haven't changed. There may be 4 small classes where there was only one large one, it might have been changed to use/not use a database, etc. On 2014 Jan 15, at 9:03 AM, Mateusz ?oskot <mateusz@...> wrote: So unit tests (or, as I now prefer, micro-tests) are around implementation, but not around the implementation of the precise thing you are testing. Unit tests, after all, test that the intent of the programmer is satisfied and the intent of the programmer has a lot to do with internals. -- C. Keith Ray *?(650) 539-4729 *? *? |
Re: [TDD] Re: Single assert / Single mock rule in practice
Mateusz ?oskot
On 15 January 2014 03:26, Charlie Poole <charliepoole@...> wrote: Charlie, you've nailed exactly what I've misunderstood.
Right, that has been clear to me, in theory. ?
? Thank you very much. Best regards, -- Mateusz ??oskot, |
Re: [TDD] Re: Single assert / Single mock rule in practice
On Tue, Jan 14, 2014 at 5:31 PM, Mateusz ?oskot <mateusz@...> wrote:
Yes, by definition, because you are testing the way the "unit" works. It is necessarily coupled to the interface of the object you are testing, though not necessarily to its internals. If the test is coupled to the internals of the object that is a failure of encapsulation and there is probably a detectable code smell.?
?
If you use a test double it should be for a direct collaborator and verify that the object under test communicates with that collaborator according to its interface contract. If you are doubling things that aren't direct collaborators that is another design smell (see Law of Demeter.)?
?As for the last part, if the behavior changes and the test doesn't have to change I would wonder if it was really testing anything. A good microtest tests one permutation of one behavior of one object. If that behavior changes the test should break. Only if the structure changes but the behavior remains the same (which is the canonical definition of refactoring) should the test not break.?
|
Re: [TDD] Re: Single assert / Single mock rule in practice
Unit tests _are_ about implementation at a certain level, and about interface at another. The difference is that we are talking about the "interface" of a class, which may be buried deep in the application. So that interface is part of the implementation of the next level up. What might be considered an "internal" for one test is then part of the interface for another test.Charlie On Tue, Jan 14, 2014 at 2:31 PM, Mateusz ?oskot <mateusz@...> wrote:
|
Re: [TDD] Re: Single assert / Single mock rule in practice
Mateusz ?oskot
On 14 January 2014 16:31, Avi Kessner <akessner@...> wrote: Best regards,
Yes, I've come up to this conclusion after some time. ?
Indeed, and that is a matter of my concern. I'm testing the implementation and somewhat implicitly I'm assuming this particular test verifies the foo.exists() - as the foo.exists() is implemented in such way that if get_item returns?
id equal to the id that is being tested. ? Yes, I agree it is an unfortunate test, or it is a different test, hence my questions.
Yes, I will have to re-write the test and as far as I understand it is nothing uncommon. I admit, this also confuses me a bit. Isn't a unit test somewhat tightly coupled to implementation?
Isn't the fact that I create a mock for a dependency used deep in implementation of method/behaviour under test, isn't it exposing implementation details, hence coupling the test and increasing risk
of reimplementing test if the method/behaviour under test changes? AFAIU, this risk is included in price of unit tests, low level tests, isn't it? -- Mateusz ??oskot, |
Re: [TDD] Re: Single assert / Single mock rule in practice
"I could have replaced
self.assertTrue(item_exists) with foo.xdep.get_item.assert_called_once_with(1)" These two things are not?equivalent?tests. ?your first assert, is correct and is testing the interface. ?You expect the item to exist if get_item returns the value of 1. Your second assertion is testing the implementation. ?What if you later change the get_item function to return an object instead of the item id? ?Do you really want to re-write this test? brought to you by the letters A, V, and I
and the number 47 On Tue, Jan 14, 2014 at 6:18 PM, Mateusz ?oskot <mateusz@...> wrote:
|
Re: Single assert / Single mock rule in practice
Mateusz ?oskot
On 14 January 2014 12:05, Mateusz ?oskot <mateusz@...> wrote:
2) What about having both assertions, would that break the single 3) AFAIU, it's natural that unit tests are coupled with implementation ofI'm re-reading my own post and realising, aren't 2) and 3) breaking the guideline [1] about writing tests to the interface, not the implementation? I think the original version of test_exists_ExistingItemId_ReturnTrue I've got is written to the interface and mocks only bare minimum of required dependencies. Anyone could help me out to get in order with terminology vs practice vs best practices here? How much unit tests should know about implementation of what is being tested? [1] "Stop Mocking, Start Testing" Augie Fackler and Nathaniel Manista at Google Best regards, -- Mateusz ?oskot, |
Single assert / Single mock rule in practice
Mateusz ?oskot
Hi,
I'd like to ask for ideas of best practices in case of developing and testing a wrapper for a Python legacy module. Especially, about applying the single assert / single mock rule which I have been learning about from numerous books/videos/blogs. I have Python xdep module which exposes API in form of bunch of free functions. I'm creating new Python module foo which uses xdep (the idea is to provide simplified, Pythonic interface, but that is not directly relevant to my question here). I'm trying to keep the code as simple & generic as possible, so my question is not about Python but unit testing and mocking. # xdep.py def open(): ... def get_item(item_id): ... def close(): ... # foo.py import xdep def exists(item_id): xdep.open() item = xdep.get_item(item_id) xdep.close() if item: return item.id == item_id else: return false Here is my module to unit test behaviuour of the foo: - I create and plug a stub for the legacy module xdep - I mock functions of xdep # test_foo.py import unittest import unittest.mock as mock class ItemTest(unittest.TestCase): def setUp(self): # create stub for external dependency of foo self.xdep_stub = mock.Mock() patcher = mock.patch.dict('sys.modules', {'xdep': self.xdep_stub}) self.addCleanup(patcher.stop) patcher.start() # import foo does import xdep, as patched above import foo self.foo = foo def test_exists_ExistingItemId_ReturnTrue(self): foo = self.foo # Arrange ### Data item_id = 1 ### Mock foo.xdep.get_item.return_value = 1 # Act item_exists = foo.item.exists(item_id) # Assert self.assertTrue(item_exists) I have a single assertion and I use single mock which mocks xdep.get_item function, so it seems a valid yet clear unit test. Now, having the single assert/single mock rule in mind, I have some questions, about the test_exists_ExistingItemId_ReturnTrue in particular: 1) How asserting on foo.item.exists return value is different from asserting how xdep.get_item mock was called? I could have replaced self.assertTrue(item_exists) with foo.xdep.get_item.assert_called_once_with(1) 2) What about having both assertions, would that break the single assertion rule? self.assertTrue(item_exists) foo.xdep.get_item.assert_called_once_with(1) I'm not concern about breaking the rule as technical convention, but as: am I testing multiple things here? 3) AFAIU, it's natural that unit tests are coupled with implementation of method/behaviour they are testing, foo.exists function in my case. So, given that foo.exists function calls three functions of the legacy xdep module xdep.open xdep.get_item xdep.close should I mock all the three function and verify how they were called? Would that still belong to scope of test_exists_ExistingItemId_ReturnTrue test or I better create a new dedicated test case(s), something like test_exists_IfCalled_xdepOpenCalled test_exists_IfCalled_xdepCloseCalled test_exists_IfCalled_xdepGetItemCalled and do assert_called_once_with() appropriately. Above, I count each mock for each xdep function as a separate mock, so "single mock per test" rule seems to suggests I should verify they are called in separate tests, doesn't it? Also, some of other xdep functions need to be called with multiple parameters, and as setting up and verifying their mocks may be quite elaborate,my gut feeling tells me that single unit test per "legacy API call expectation" as listed above is a good approach for readability and maintainability of tests. Am I right? 4) What other, if any, approach to single assert/single mock rules would you take for testing similar case as above? Best regards, -- Mateusz ?oskot, |
Re: [TDD] Re: A worked example of TDD in D, with some personal ruminations on my own style, and notes on the D language..
¿ªÔÆÌåÓýWow, I had missed that blog post. Fascinating. Thanks!R On Jan 7, 2014, at 8:15 PM, John Carter <john.carter@...> wrote:
Ron Jeffries |
Re: [TDD] Re: A worked example of TDD in D, with some personal ruminations on my own style, and notes on the D language..
Missed the original post ... so many thanks for sharing! Wish this group were more active. On Tue, Jan 7, 2014 at 7:15 PM, John Carter <john.carter@...> wrote:
|
Re: A worked example of TDD in D, with some personal ruminations on my own style, and notes on the D language..
Pity I didn't see this blog post first.... Because then I would have defined "Provocative Test that adds one new Behaviour" as one that provoked one new behaviour in the precedence order suggested by Uncle Bob.?? On Mon, Dec 30, 2013 at 9:40 AM, John Carter <john.carter@...> wrote:
--
John Carter
Phone : (64)(3) 358 6639 Tait Electronics? ? ? ? ? ? ? ? ?? ? ??? PO Box 1645 Christchurch New Zealand This email, including any attachments, is only for the intended recipient. It is subject to copyright, is confidential and may be the subject of legal or other privilege, none of which is waived or lost by reason of this transmission. If
you are not an intended recipient, you may not use, disseminate,
distribute or reproduce such email, any attachments, or any part
thereof. If you have received a message in error, please notify the
sender immediately and erase all copies of the message and any
attachments. Unfortunately, we
cannot warrant that the email has not been altered or corrupted during
transmission nor can we guarantee that any email or any attachments are
free from computer viruses or other conditions which may damage or
interfere with recipient data, hardware or software. The recipient
relies upon its own procedures and assumes all risk of use and of
opening any attachments. |
Re: [TDD] A worked example of TDD in D, with some personal ruminations on my own style, and notes on the D language..
Osias Jota
#likedthispost On Sun, Dec 29, 2013 at 6:40 PM, John Carter <john.carter@...> wrote:
Osias, o Osias |
A worked example of TDD in D, with some personal ruminations on my own style, and notes on the D language..
So I have being doing TDD for years now. But I started noting I tend not to do it exactly "By The Book".?Conclusions from the exercise.
Bottom Line?In future I will be doing...
What do I mean by provocative test cases? For example, when converting Roman numerals.
"I" is provocative. "II" is provocative. "III" is NOT provocative, it merely is extra Lines of Code (and hence a liability). "IV" is provocative, but a bad choice for next test case as it adds two new behaviours at once. "V" is provocative and adds a single new behaviour. "IV" is now provocative and adds only a single new behaviour. ? Conclusions about D.?I love it. ?It is C / C++ with the worst stuff removed, and the best stuff stolen from it's competitors. ?If you are serious about industrial grade, high quality, defect free, efficient programming, you urgently need to be looking at D as your next language. ?Sigh! Unicode. ?That's not D's fault. ?D handles Unicode remarkably smoothly, but ye ancient 7bit ASCII is always going to be faster and conceptually easier than variable length code point UTF8. ?It took a bit of time and effort to get my head around D's template system (richer, safer, better than C++) ?It took even more time to get my head around Ranges, (again, richer, more flexible, safer than C++ iterators, more efficient than generators, coroutines or enumerators.) ?The choices D has made are rich in very powerful, very efficient implications. Possibly the most striking is Compile Time Function Evaluation. If it can be evaluated at compile time.... in D it will be. And that is startling powerful. -- John Carter
Phone : (64)(3) 358 6639 Tait Electronics? ? ? ? ? ? ? ? ?? ? ??? PO Box 1645 Christchurch New Zealand This email, including any attachments, is only for the intended recipient. It is subject to copyright, is confidential and may be the subject of legal or other privilege, none of which is waived or lost by reason of this transmission. If
you are not an intended recipient, you may not use, disseminate,
distribute or reproduce such email, any attachments, or any part
thereof. If you have received a message in error, please notify the
sender immediately and erase all copies of the message and any
attachments. Unfortunately, we
cannot warrant that the email has not been altered or corrupted during
transmission nor can we guarantee that any email or any attachments are
free from computer viruses or other conditions which may damage or
interfere with recipient data, hardware or software. The recipient
relies upon its own procedures and assumes all risk of use and of
opening any attachments. |
I'm looking for a new challenge
Hi All. I hope this isn't spamming the list, but I could not think of a better suited place to post. I'm looking for a job and I would love to hear from you if you live in a place warmer than Norway :) Why and where:??
My cv is at ? Thanks, Roy Osherove ?? - @RoyOsherove ?? - Author of "The Art Of Unit Testing" ) ?? - My blog for team leaders: ?? - My favorite keyboard shortcuts: ?? - +972-524-655388 (GMT+2) |
Agile & Web programming SURVEY 2013
Dear IT manager/project manager/developer,? We are two software engineering research groups working on improving methodologies and practices for Web development. We kindly ask you to contribute ten minutes of your time to answer a survey we prepared on the use of Agile and Lean Methodologies, and other practices, in Web development. The survey can be found at this link : If you choose to provide your email address we shall send you a complimentary report with the results of this survey. We shall use your email address only for this purpose.? Thank you in advance for your availability and for your time.? AGILAB, DITEN, University of Genoa and AGILE GROUP, DIEE, University of Cagliari, Italy. |
Re: [TDD] Test Driving WPF
¿ªÔÆÌåÓýPlease trim down posts. A long thread does not require emails of increasing length. Try to quote only the material you need, and trim the rest.Thanks, Ron Jeffries |