Keyboard Shortcuts
Likes
- Testdrivendevelopment
- Messages
Search
Re: How would you respond?
On Wed, 2 Sep 2020 at 15:28, Russell Gold <russ@...> wrote:
Note that the context here is not greenfield TDD but bringing existing code that starts entirely without tests into testing and refactoring along the way initially via characterization tests etc.? The comment above should not be read without that background context as it could otherwise be potentially misleading.? -- Given you start with code without tests there's going?to be some tests being written after the fact, though then even still, you could argue that you could/one should start TDD'ing at the point where you have your characterisation tests and start refactoring towards a new object (say), which if done in that way, would mean you should not then end having to further write "symemetrical" unit tests after the fact.? Perhaps that was your point and I'm just slow catching on.? Still, for the benefit of others just mentioning the context as I initially read this and got slightly the wrong idea without that context.? |
||
Re: How would you respond?
开云体育Wow, that’s depressing.For me, this is a major portion of the disconnect: Even after the refactor is completed successfully, more work remains! To ensure that every unit in your system is paired with a well-designed (I call it “symmetrical”) unit test, you now have to design a new unit test that characterizes the behavior of the new child object. But he does raise a concern that I have recognized: most people don’t refactor because they don’t sense the code smells. Most developers don’t know what good code looks like. ?have often used Martin Fowler’s Video Store sample to demonstrate refactoring, and when I ask for opinions of the original code, most people say it looks good; they tend to judge code primarily by how much effort is involved in trying to understand it. That suggests that the most important lesson to be taught is the recognition of bad code, probably by teaching why code smells matter.? In Uncle Bob’s “Clean Code,” he notes the rule about avoiding “magic numbers.” That advice is hardly new; I have books from the 1970’s making the same recommendation, and yet programmers routinely violate it. Yourdon and Constantine wrote about coupling and cohesion in 1975, and yet most code I see shows that even very senior programmers fail to internalize those rules. In some ways, we aren’t making a lot of progress.? ----------------- Author,?Getting Started with Apache Maven <> Author, HttpUnit <> and SimpleStub <> Now blogging at <> Have you listened to Edict Zero <>? If not, you don’t know what you’re missing!
|
||
Re: How would you respond?
But the art in TDD is finding the next test which forces the code to move towards the design you want.I think this difficulty is more or less the driving motivation behind Justin Searls' London-style approach to TDD. Here's a choice quote: The first test will result in some immediate problem-solving implementation code. The second test will demand some more. The third test will complicate your design further. At no point will the act of TDD per se prompt you to improve the intrinsic design of your implementation by breaking your large unit up into smaller ones. The full thing is well worth a read:?. |
||
Re: How would you respond?
I can see how those paragraphs can be ambiguous. I didn't originally read them the way you are reading them now.? As for the tests dictating the design. I think this is where most people get stuck. (e.g. they start writing posts about how TDD is an antipattern) The tests help guide the design, and help you see if your design is working. But the art in TDD is finding the next test which forces the code to move towards the design you want. It doesn't dictate the design by forcing the implementation, it guides the design by enforcing the desired behaviors, and helps you check that the design is correct. On Wed, 2 Sep 2020, 01:08 , <rold9888@...> wrote:
|
||
Re: How would you respond?
Quite possibly. I'd trace this back to the article, with a couple of paragraphs quoted by way of example:
And the final paragraph
Given that there are people out there who would argue that TDD is a design activity *before* it concerns itself with having tests to catch regressions, this last point is in my view an inappropriately strong claim to make, and represents my biggest problem with the article. In particular, if tests don't drive the design of the code, and aren't being used to anchor down the behaviour of small units, then I'm not sure what argument the author offers in favour of writing the tests before the code, which is pretty much the only thing that unites different TDD practitioners of all stripes AFAICT. |
||
Re: How would you respond?
Note that if you're using automated refactoring tools, they will refactor the test code and the application code at the same time. It's a big win to think of editing in terms of concepts instead of lines of code or characters.
toggle quoted message
Show quoted text
- George On 9/1/20 11:37 AM, rold9888@... wrote:
A 'unit test' of SomeClass#some_instance_method might still be fairly structure insensitive (if the method involves any dependencies, private methods of SomeClass, whatever). But that unit test cares, at the very least, about --
---------------------------------------------------------------------- * George Dinwiddie * Software Development Consultant and Coach ---------------------------------------------------------------------- |
||
Re: How would you respond?
I think there is a distinction between testing behavior vs testing implementation and testing the end user?experience / acceptance tests that is getting muddled here.? On Tue, 1 Sep 2020, 19:36 , <rold9888@...> wrote: Sure, it wasn't my intention to claim either that the tradeoffs are entirely due to mocks, or that mocks aren't a good way of isolating a test subject from its dependencies. Sorry if I was unclear.? |
||
Re: How would you respond?
I very much agree about the tradeoffs.? I disagree about attributing all the tradeoffs to mocks.? Sometimes mocks are the most expedient way to purely unit test an object in isolation from the objects it calls. On Tue, Sep 1, 2020 at 8:37 AM <rold9888@...> wrote:
|
||
Re: How would you respond?
So the biggest difference between the two schools of TDD I mentioned is in their use of mock objects, but there's broad agreement that mocks act as an impediment to some refactorings. People who use mocks extensively do so because they think the trade offs are worth that particular price. Beck wrote the foreword to the book "Growing Object-Oriented Software Guided by Tests" which is the canonical reference for London-school TDD, and was still very complimentary about the book whilst acknowledging that it isn't how he personally practices TDD. To be clear, I don't disagree that structure-insensitivity of tests is a highly desirable property, just with the claim that anyone who doesn't exclusively test an application from the perspective of an end user "doesn't understand" TDD.?
As soon as you write such a test, you expose yourself to the possibility that a refactoring can break that test. As a trivial but concrete example, say you're working on a web app backend with an MVC structure. Your controller handles anything to do with the web layer, including params and rendering a response, but delegates all business logic to SomeClass#some_instance_method. A 'unit test' of SomeClass#some_instance_method might still be fairly structure insensitive (if the method involves any dependencies, private methods of SomeClass, whatever). But that unit test cares, at the very least, about
And likely also how to instantiate an instance of the class or set dependencies, unless you're using some sort of factory or an IoC container like Java Spring. Changing any of these things, together with how they are invoked in the controller action, is a refactoring that the user does not care about, but will force you to make the corresponding change in your test.? There's a tradeoff. Testing smaller units of functionality makes your tests faster to run, easier to write, likely easier to read, more focussed as bug detectors, and helps you manage the internal structure of your code. Your tests being sensitive to things the user doesn't care about is the price you pay for these benefits. Different people value these costs and benefits differently, to the extent that the Chicago and London schools can be recognised as distinct approaches, but even within each school people make their own choices about this compromise (and others) on a smaller scale every time they write a test IMHO. |
||
Re: How would you respond?
Some quotes from Kent Beck. I call them "unit-tests," but they don't match the accepted definition of unit test very well. -- Kent Beck, Test Driven Development by Example (2003) Structure-invariant tests requires a particular style of programming and design as well as a particular style of design. I frequently see tests that assert, “Assert that this object sends this message to that object with these parameters and then sends this other message to that other object.” An assertion like this is basically the world’s clumsiest programming language syntax.?If I care about the order of operations, I’ve designed the system wrong. ...?
When refactoring causes tests to fail, that's when you learn you are writing your tests wrong. The only way to avoid that is to focus on the behaviour you are expecting. brought to you by the letters A, V, and I and the number 47 On Tue, Sep 1, 2020 at 12:47 PM <rold9888@...> wrote:
|
||
Re: How would you respond?
I think my response would be somewhat similar to that of the comments. (FYI, to make the comments visible click the link that says "25 responses" below the article.) The only caveat I would express here is that Beck was writing in an era of Smalltalk GUI apps, under the assumption that without "programmer tests" (tests of small units of code, as the article cautions against) the time taken to write a system-level test and get it passing is measured in days. If I think about a modern Rails app, for some simple functionality it might take an hour or less to write an integration test and the code to make it pass, so this might change that calculus. Nevertheless, this is a professional judgement call. I don't think that the decision to write unit-level tests in this situation would reflect a lack of understanding of TDD on Beck's part. |
||
Re: How would you respond?
Huh, I'm curious why others can't see the comments. I don't have a Medium account as well. I wonder if it's because I got the link through AMP. brought to you by the letters A, V, and I and the number 47 On Mon, Aug 31, 2020 at 4:11 PM Tom <rossentj@...> wrote:
|
||
Re: How would you respond?
Reposting the main comment which got the most likes. "You’re arguing against what would classically be described as unit tests (without ever actually using that term) while arguing in favor of something else you never ascribed any name to. By your examples, that something else seems to be more on the integration test, behavior-driven test, or end-to-end test end of the spectrum. I think it’s critically important to understand that many different kinds of tests exist, they have established names, and they?complement?one another. You’re right that there is tremendous value in tests that operate from (or closer to) the perspective of a user, but that’s one?kind?of test that really should be supplemented with other kinds of test as well. You usually cannot cover all your bases with just one type of test. Someone told me once that behavior driven tests assert you’ve “built the right thing,” whilst unit tests assert you “built the thing right.” That’s an important distinction. Unit tests?can, indeed, be brittle, but that should be expected, because they are intimately and inextricably related to the most?low-level?bits of your code. At that level, you can assert things that you cannot assert from several layers of abstraction up the stack. At the end of the day, it’s the only way to catch a certain class of bug that other forms of testing will never find. A thought on the mechanic analogy — mechanics perform maintenance. Software engineers do as well, but that role is largely incidental. “Engineer” is in our title. We design. We build. Mechanics don’t do that. It’s not unfair to say that comparing software engineers to those who maintain automobiles is a less apt comparison than one to those who?design?them — or to those who design individual automotive parts even. I can assure you that the automotive industry doesn’t rely solely on testing of fully assembled vehicles to assert things work as they should. Before your car’s HVAC system was designed and eventually assembled, there was a radiator that was known to generate heat, a compressor that was known to compress, coolant that was known to cool, and fans that were known to blow — all within their own individual specifications. Bringing this analogy back to software, one could ask what is point of integration testing a suite of components that aren’t individually known to meet their own specifications. When that system inevitably fails, it’s anyone’s guess which component was responsible, and that’s when you start to wish you’d unit tested." Then follows many comments saying things like, you aren't describing TDD, you are describing BDD. Or , this only applies to integration tests, or, TDD has to cover every line of code, so it can only work on implementation details, etc. On Sun, 30 Aug 2020, 15:04 Ron Jeffries, <ronjeffriesacm@...> wrote:
|
||
Re: How would you respond?
开云体育Comments not visible to me. I do not subscribe to Medium (and do not plan to). Maybe that's why the comments didn't show up.Good general advice: never read your reviews, never read the comments. :) I thought the article was pretty weak but aside from the click-bait and artificial argumentation, I didn't see much to object to. R
Ron Jeffries |
||
Re: Event Modeling and TDD... somewhat
Having developed a couple of CQRS event sourced systems, I found TDD to be a perfect companion. The Given ( events[] ) When( command() ) Then ( resultingEvents[] / resultingState ) pattern lends itself really well to developing a test DSL, creating a very solid core of logic that is easy to reason about.
There are of course tricky things that need to be dealt with, like eventual consistency, transactional properties, modelling external input properly, designing aggregate granularity, that need careful design that TDDing it will not automatically flesh out for you, but for developing the core logic, it is a perfect match. |
||
Re: How to learn good design using TDD ?
Thanks for the correction, and sorry for not crediting Kent Beck. I like the point Jeff made, by refactoring your code you can also try different solutions "to find the one that seems most expressive", this is definitely tied to design. While I was writing the first message, I was wondering if there's some previous work on this subject and immediately thought to Apprenticeship Patterns by David H. Hoover and Adewale Oshineye. (I dug a bit and found also Pragmatic thinking and learning by Andy Hunt, which I've not read, sorry) In apprenticeship patterns thre's 3 related patterns: ?- "create feedback loop": TDD is cited (personally I've also used metrics like cyclomatic complexity to get feedback, it can temporarily help) - "breakable toy" and "practice, practice, and practice" which are linked to TDD by the safety environment it provides to experiment and gain confidence in our work. Also increasing the number of assessment as an impact on retention (cf. ) and all these patterns are kind of assessments, they help to form "many associations with other things in the mind". I made another experiment when I started to learn elixir, by sharing a pimped version of my own learning support (which I falsely called koans). Aftermaths I believe it should be something more personal because nobody can do the job to memorize for you . Even if Koans are great, they make you follow someone else's path which tends to give answers before you have the time to ask yourself the questions, it's a bit less efficient. (see Stephen Downes on personalized vs personal learning) Le?sam. 8 ao?t 2020 à?22:49, <rold9888@...> a écrit?: On the subject of learning a language via TDD: of related interest is that for many languages you can find "<Language name> Koans", where someone has already written a suite of failing unit tests of language features, complete with helpful error messages that allow you to get the tests passing. I first learned of it via??which I believe to be the original, but it's easy enough to Google e.g. "Java Koans" and find something like?. |
||
Re: How to learn good design using TDD ?
开云体育A few months ago, I used TDD to learn some Kotlin basics. While I could make Green code, I needed help with the Refactor step. It came in two forms: ? The IDE itself offered suggestions. ? Viewers on Twitch wrote comments as I was coding. Both are forms of community knowledge. The first set is encoded in a tool. The second set came from mobbing/ensemble programming.
|