πŸš€ TDD, Where Did It All Go Wrong (Ian Cooper)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

This is a seriously good talk. Even if you don't like TDD there are a lot of good general advices about writing unit tests in this.

πŸ‘οΈŽ︎ 102 πŸ‘€οΈŽ︎ u/Indie_Dev πŸ“…οΈŽ︎ Jul 30 2021 πŸ—«︎ replies

This is one of the best talks I ever listened to. Immediately changed the way I worked.

πŸ‘οΈŽ︎ 21 πŸ‘€οΈŽ︎ u/[deleted] πŸ“…οΈŽ︎ Jul 30 2021 πŸ—«︎ replies

This is an eye opener. Let my notes speak for me:
- Test requirements, not low level
- Test public API. Given when then
- Test the exports from a module
- Focus on higher-level
- Test modules, not classes
- Test behaviors, not methods
- Think about your code as an API
- Test the abstraction, not the implementation
- Test are isolated and with shared fixture (to run quickly)
- Red-green-refactor (go fast to working code)
- No new tests during refactoring
- Heavy coupling is the problem with all software
- Thin public API
- Refactoring = changing internals
- Patterns in the refactoring
- If you're not really sure, write tests for implementation (delete the tests)
- Don't isolate classes in testing
- Private methods are implementation details

πŸ‘οΈŽ︎ 124 πŸ‘€οΈŽ︎ u/TheLeadDev πŸ“…οΈŽ︎ Jul 30 2021 πŸ—«︎ replies

You should also watch Improving your Test Driven Development in 45 minutes - Jakub Nabrdalik https://youtu.be/2vEoL3Irgiw. I 100% believe that one of the places TDD went wrong is we all started writing unit tests with mocks and cemented our terrible architecture in place. That being said IDK if anyone like Kent Beck ever said we should do this. I wonder if this is something we just ended up twisting. There is a 5 series discussion between Martin Fowler, Kent Beck, and DHH about this that I feel like is entirely about this. Here is a link to them https://youtube.com/playlist?list=PL0psd9osbCd1qSZM7XKG2qZdX7nDDj8to

πŸ‘οΈŽ︎ 16 πŸ‘€οΈŽ︎ u/dmstocking πŸ“…οΈŽ︎ Jul 31 2021 πŸ—«︎ replies

I want to do better testing. I usually just write class/method unit tests probably overusing mocks.

Most projects I've worked on, there are either no tests or abysmally bad tests.

Writing unit tests was the easiest way to for me to start testing.

  • They are cheap to write. I spend maybe 4 hours adding tests for code that took me a week to write.
  • They are cheap to throw away. I freely delete tests if there is refactoring.

Testing for me is a way re-exploring the code I've written to ensure that it works the way I expect. It's also made me much more inclined to think about my code more. I make large chunks of code into smaller, more sensible bits.

The biggest roadblock for me is that it has to be completely self driven. None of my coworkers are supportive of it. No one wants to discuss how testing could be better. No one wants to stand up for making sure there is time to improve testing practices.

It takes time. No one has respect for the learning curve.

I forced myself to learn unit testing when I joined a company some years ago that had a useless test suite. My team didn't help in this endeavor, but I was new and no one really cared if the work I was doing took an extra week. Today, I'm at another company. There's no way I could ever slip a week in to start working on the things we'd need to follow advice like what Ian Cooper is suggesting.

How can you overcome the the sense of hopelessness when no one else seems to care about testing?

πŸ‘οΈŽ︎ 13 πŸ‘€οΈŽ︎ u/PunchingDwarves πŸ“…οΈŽ︎ Jul 31 2021 πŸ—«︎ replies

Ian is too restrictive to suggest "to avoid the mocks." There are a lot of cases where mocks are the best approach for testing.

Imagine you are testing procedural code on C that draws something in the window. Its result will be painted in the window, and usually, you can't compare the window state with the desired image.

Checking that your code called correct drawing functions with correct parameters seems natural in this case. and you'll probably use mocks for this.

I like Fowler's article about this more than what Ian is talking about. https://martinfowler.com/articles/mocksArentStubs.html

πŸ‘οΈŽ︎ 24 πŸ‘€οΈŽ︎ u/Bitter-Tell-6235 πŸ“…οΈŽ︎ Jul 30 2021 πŸ—«︎ replies

I have a question on this someone might be able to answer.

I really like the idea of just testing the API and not trying to test individual classes/methods. The bit I struggle with is, say I have an method which is meant to get a percentage of a number. I want to verify with a few different inputs that it's returning the correct percentage, but I don't expose this class directly to the API. So I could write a test that targets a specific API call which just happens to use that percentage code (and then verify in the returned API results that my final result matches what I expect), but the API call I have to make involves a ton of other code which has to run in order to hit that percentage class. If my test breaks, I don't know if it was because of code in my percentage class that failed, or something in the huge amount of other code it has to walk through which failed. It also makes refactoring tricky - perhaps in that code which I called through the API someone realized they don't need the percentage call in there anymore - now confusingly a (seemingly unrelated) test which was trying to target that percentage check falls over. That would be very confusing.

You could say "well, the percentage class isn't what you are testing - if the behaviour is that when adding tax to something it needs to come to the asserted amount, whether or not it uses that percentage class is irrelevant - you are testing the final result". Which I think is fine, but then a test that checks for adding a percentage of tax starts to look identical to the test which is verifying that tax didn't exceed a certain amount, or handled decimals correctly, or took some sort of localization into account. Since these all hit the same code and run the same API call in the test, but I want to verify different things, I could end up with 20+ asserts all in the same test. Is this...ok?

πŸ‘οΈŽ︎ 2 πŸ‘€οΈŽ︎ u/turboknight πŸ“…οΈŽ︎ Aug 01 2021 πŸ—«︎ replies

TDD went astray when TDD projects had the same rate of delay & defects as non TDD projects. /anecdote != data

Evangelists claim it is the people or the method, not the idea, which while true, could just mean TDD is a rough road for the average mortal. Successes and failures litter the landscape.

Could it be TDD is NP? ...

Robotics have been emerging for a while. many bridesmaids but so far nary a bride. hope springs eternal!

πŸ‘οΈŽ︎ 5 πŸ‘€οΈŽ︎ u/constant_void πŸ“…οΈŽ︎ Jul 30 2021 πŸ—«︎ replies

It’s pretty simple - TDD is an almost meaningless term, because there’s soooo many different ways to do it. Your tests are brittle? Oh, well you did too much mocking. You have to update your tests with every single change, oh well they weren’t testing behavior correctly. What is behavior exactly? Don’t worry about that, just keep writing tests. Your frontend tests don’t seem valuable? Well, who said you should test frontend code?

If you read the original TDD book, Kent Beck applies it to a Money class. It’s a value object that has methods for adding values of different currencies together, stuff like that. Why did we think that idea would scale to the entire system, and be applied in the same way across the stack?

Now, I still write a lot of tests, because I don’t know of a more practical way currently to prevent things from getting broken on a project that’s under active development. But it’s pretty clear that TDD will not magically save your project. Tests are a very large cost, and should be used wisely.

πŸ‘οΈŽ︎ 1 πŸ‘€οΈŽ︎ u/editor_of_the_beast πŸ“…οΈŽ︎ Jul 31 2021 πŸ—«︎ replies
Captions
um just a quick sort of show of hands or a couple of questions from the audience how many of you have actually seen a video of me doing this talk at any point few of you okay there are some nuances and giving it live would be a bit time bit different but you're seeing the gist of the argument how many of you are using tester from government today test first the test after okay how many of you are doing it you know test first all right and how many of you are using so mock mocking techniques and mocks okay two loads you okay very interesting okay this is me most of that is dull and uninteresting but that I usually draw attention to is the last point on that slide which is people like me come and talk at conferences to stand in front of you we're not necessarily smarter or cleverer than any of you guys and you know I'd really encourage all of you to gallop and speaker conferences if you can contribute back to the community that's all what I'm doing is I'm just a developer like you who decided to try and share some of my ideas with everybody else I kind of got forced into it because back when dotnet first started there were very few people to reverse the experts and so as such you know if you wanted to run a meet-up or a user group you had to kind of start up and do it yourself but I'd encourage all of you to get involved if you can it's a great way of personal growth for you as a developer in terms of learning to express your ideas more clearly that's how I work for I work for huddle it's not really that exciting we are hiring by the way but it's not that really exciting for you other than just to say we are a SAS software business I have nothing to sell you right you can't buy my services so one of the ideas here are based simply on my experience I'm trying to share with you not on me trying to basically market anything to you we can talk about today so I want to talk about what I perceive as being the problem with how people are practicing TD today and why there has been growing resistance to TDD I want to then look at rebooting RTD practice taking us back already to where we started from I'm looking again ideas like red green refactor green code refactoring etc until I understand how those ideas should be applied where we may have made mistakes in our practice that have led us to adverse ways of doing TDD and then I'll talk about some ideas that can help ports and adapters gears look at what a team behaved right and give us and Mach squad to get through some of the later sections we may go a little bit faster on depending on time so we'll try and focus on the early sections first thing I do is talk about the problem now I have been practicing TDD since about 2004 in London the dotnet community were quite early adopters of test-driven development just simply because we had close relationships with an XP group that used to meet in London and a lot cross-fertilization of ideas and so we were into practicing a PDF or quite a while and I first gave this talk in about 2013 so I've been roughly 10 years I've been doing TDD and I had come to the conclusion after owning TDD produced test Suites for a while that there were some problems of what we were doing and you know one of my things is that I tend to try because let's become a software architecture on stair companies long enough to see my own mistakes come back to meet me it's a very humbling thing to do but it's also how you gain kind of a lot of value from your experience if you stay somewhere two years quite often the problem is that you don't ever see you finished implementing something you're very proud of this great work you've given the need done and you move off and you never find out what we're all the things that you actually did wrong that later developers went right about so if you'd stay a bit longer quite often you find what goes wrong and I have written quite extensive test Suites and I found some of them were very difficult and very expensive to own so that's going to talk about my understanding of TDD and attach shifted over the years okay so the first thing was back in 2005 2006 when Alice first haven't drunk the kool-aid on TDD if I was practicing TDD I found quite a lot of resistance to test driven development lot of people were saying we don't want to do this this is a crazy idea and I was very much you just don't get it you just don't get what the rest of us get you know this is the best best change in development practice I've seen in the last 10 years you guys need to be doing TDD you just don't get it but still the people saying well I just I'm not really sure about this TDD this crazy thing is a lot of those guys were really quite smart developers who I respect it you know these are guys who wrote really good code yet they were saying to me this TDD thing it's not the right way to develop software Anna you know the more they said this the more just kept repeating the TDD mantras as if like a child if I just kept speaking slowly and carefully and repeating how TDD worked eventually the light bulb would go off and they would appreciate the glory that was TDD but a few of them just seem to resist I can be one of them a really smart developer at law I you know really really admired his work said to me one time it's okay and I finally got it and that's like and he said the junior developers they need TDD it really helps them I can see how it helps them write good code but surely you don't really expect the experienced developers on the team to be doing TDD right and I was really puzzled I couldn't really understand what is this guy getting it a couple of times we're very proud of the fact that we produced some code went into production with almost zero defects so there's no UI evolving like that bit easier but one time I worked on our back-end service and that went to production and for a year there were no reported defects what exactly's expected we were very proud and we put down the you know but down that way this had worked at EDD we had a fantastic test suite we knew all the scenarios we were going to operate under and provably our code worked all I looked at this test suite one of the things I noticed was that we had about three times as much Tesco as production code and I can remember being a little bit mmm is this right so I went onto Twitter source of all answers to all questions in life in universe their source of truth and wisdom and I said to twitter twitter is this right you know yeah no no we caught often have you know two or three times the amount test code that we have basically is actual production code I was thinking it's okay but it feels a bit puzzling one of the problems with this is you quite often got the situation where you know some project manager would turn around and say guys could we just skip the tests we've done so much faster we get out to market a lot faster I know you guys like doing good engineering except you're on I really get that but it's taking us an awfully long time to write all these tests couldn't we just ship the code you wouldn't really matter if there were a few defects you know in production right can we just not do the test and we'd say no no no you don't understand the way we write code is by writing tests we can no more stop writing the tests let me collect this is all right into the standard mantra admittedly you know tests are part of our practice for writing code you're just telling us to stop writing code if you do that and red go away you go okay fair enough we get it you know you guys want to write tests but we were slower I mean ssyn reality we were you know twenty to fifty percent slower than we had been before by writing tests the other thing I noticed over time was there's so many big test Suites is that when we wanted to change something we've quite often break a lot of the tests and quite often what we were doing was simply refactoring we were going oh well we've added some new features to the code and now the shape of the implementation is a bit wrong giving these new features and I can think of a better way of organizing our code make you more maintainable so I'm going to refactor the way the code is organized I want to change the behavior of the system I just want to reflect of the shape of the code so that essentially it's more efficient but how other tests would break and all the time the tests that broke were the ones that basically that were heavily marked because these mocks we're telling this exactly what ought to be happening in the calendar test they were saying old first you should be cooling this twice then call this and then put call this and put these parameters on it when we refactor something we quite often changed how that worked all these tests with mocks they broke and we had to rewrite all the mocks it was kind of puzzling right because the promise was that we should be able to refactor our code keep it basically fit and clean we wouldn't get into a big ball of mud craziness we wouldn't really see our code rot before us because our tests would enable us to refactor and refactoring kept our code healthy but we wanted to change our code actually the tests were an obstacle to that change because they increased the amount of effort we had to put into making any changes it had to fix all these tests that were breaking when we changed her implementation details and that didn't sound right because surely what Martin Fowler an account that were telling us about refactoring was that refactoring was changing the implementation details without breaking tests yet our tests were breaking all the time the other thing we began to notice was I guess it's about 2009-2010 a holiday methodologies began to emerge that explicitly said don't do test-driven development because test-driven development slows you down so there's program around okey know what program around key is you guys that reached over here ern Uncle Fred George Fred George essentially said for those who understand spinal tap references he said if XP is good let's turn the dials on XP up to 11 let's do extreme extreme programming that's basically fire everybody who isn't a software developer father QA father product guy just have developers talking to customers and what we'll do is we'll write really small pieces of code we'll call them micro services the only about a hundred lines so different schools microservices this is the original one about hundred lines of code I won't have any tests because it's such a similar amount of code you ban to get it right we'll put it into production if you want to change we'll just throw it away and rewrite it okay press record programmer Anakin but there other things like spike and stabilizer even lean software development which became the real you know go to approach of California and Silicon Valley startup we're saying don't do tests right working character customers get it out there fast as you can get feedback because you may be building the wrong thing altogether I'm gonna throw it away TDD is a kind of practice you do you like to run when you're scaling I pretend to test it slows you down too much so there's this whole pressure saying TDD is a bad idea because TDD really slows you down and he's better off just getting feedback you guys especially over here duct-tape programmer so doc tech program was this really annoying guy right and every organization has one and he's the guy that business or the product team actually love because he just gives them solutions as fast as he can and as a requirement comes out and they say let's keep it to bob bob will just get it out the door really fast and rest the team are going but this is crazy then and she ain't you going we hate Bob Bob's engineering is rubbish we spent all this time maintaining the stuff that Bob's written and having to rewrite it and it's really annoying because Bob gets all the credit right from the product guide the guy's going Bob fantastic he's so receptive to our ideas he's pushes stuff out the rest are you going but it's so hard to maintain the Bob's code is terrible right but they love Bob because Bob delivers for them you're still writing it for your test suite and bob has shipped the code and it's running okay we had a few of those and needs to be really annoying you should be really annoying that we were still doing they're doing our best engineering practices and these guys were shipping code and there's waffle code but they were shipping right and so they won the credibility not us sometimes we to come back to our tests when they were breaking quite often because we were trying to change implementation details we'd realized that we had no idea what the test was doing they don't have this experience you go back and find the test is red and you're looking at it in your going I have no idea what this test is for and I have no idea whether the fact that this red is good or bad at this point in time okay this test seems to add two numbers and come to a result which I can't possibly understand how they could have originally ever got that result and why this test was originally passing and now I've refracted it and it's red surely just because the test is wrong but lots of tests just don't really give you any information especially the ones that are like swarm with mocks and you kind of like what is actually an under test here I don't have the experience I'd look to the test and they finally realized nothing is actually being tested apart from the mocks right someone's written this thing about it so how do you go there's no real code actually under test here okay and that experience place if you began to drive us mad we're like well I no longer know what this test is for the best thing for me to do is just to delete this test because it's broken I don't know why I made to my shame a team I worked for embrace fitness and we sat down and produced basically these loving tables in HTML and they drove use them to drive our software and eventually you know these little tests would show up the page would shop green so that we could say yes these high-level tests that are the cut-in written in natural English so the customer can understand them these tests basically demonstrate that our software does exactly what we say it does on the can and spec flow cucumber these tools are all the same kind of thing the idea essentially that I will write tests that the customer can just flip through the HTML pages see the requirement we've implemented feel confident that the system does exactly what he specified because it and press the button and see or go green are the software runs exactly as I expected the gun is basically hated writing these tests because they'd start out practically nil be red in the beginning the iteration so be red for a lot of the iteration until eventually they would go green when you'd done the implementation and that meant essentially your fitness test suite was quite often well correctly read much the iteration so you could never really be sure if the tests were read is that because it's yet to be implemented or is that because essentially we we we broken it and so the thing that happened was a lot of time the tests were red because we just assumed all that red because not implemented yet when in fact they were broken so it spent a lot of their time as broken test Suites the customers never really looked at this stuff right we'd built these customer-facing tests but it was very rare to get the customers to actually come along and flip through the HTML pages and say I'm so impressed guys I can see exactly the requirements that I want I can see them written in a natural language and I I can see that it works right a cage we try and sit them down make them look at the screen and they go maybe something my calendar guys and we'll talk about this at some point in the future right and they were completely uninterested in seeing these test Suites that we written to prove to them that the code works correctly for and the check in dollars became more complicated because as well as passing a developer tests you had to run all these fitness test Suites before we allowed you to check your tests into the code base they took a while to run they were slow and that meant essentially you go for making a cup of coffee and come back essentially because really you know that's you then you'd lose track of where you were what you were doing and the whole flow of your coding session was broken because now you're in that classy developer situation won't take you 20 minutes to really get my head around the code that I'm working on and then I'm in the groove and I'm working on it but now I forced the interruption to our process which is going to mean that you stop working effectively during that time period okay so become a really efficient way of doing it and the developers just really hated doing it and they started to ignore them right if we just basically keep going and checking code in eventually and will notice the tests are all red and go by again sort of thing and then we have to basically down towards or fix them but until then we can keep moving right and then what happened was if someone would always be plausible deniability right my test didn't make that go right my change as with my change that was Davis change then used to have somebody appointed on the team whose job was to essentially determine why the who had broken the tests and made them go red and then that person would essentially blame you know apportion blame for the person that had to go and fix it right the fact that we actually had a step in our process which essentially was somebody decides who's to blame for the tests being red today and then they go to have to go and fix them implies that no one really cared about those tests because they'd reached that point at being a red the whole time really the developers couldn't see any value they constantly resisted write-ins his tests and one thing I've learned over time is that you know if an idea actually really works after a while your team will be quite happy behind it and if you get some supporters of it if your team is constantly pushing back saying we e doesn't they don't see where I'm getting from this I don't see the value in the test that you're forcing me to write and maybe you need to think again about what you're doing okay I'm about a year after I gave this talk for the first time DHH the kind of crisis is about petrol rails posted this blog post TDD is their donative testing and a lot of what his complaint was was I am being forced by people to become that rouse wrong because rouse doesn't work the way they think test friendly framework should work so he said you know I have the active record pattern rails no next record those who don't know effectively the data persistence methods own are actually on the object that you're persisting so your user object has a persistence but it's on it for object I see people tell me this is no good because they can't cleanly separate their domain object models from basically their testing framework and he said I just used to test like right my unit tests and I talked the database and I'm now told that's wrong as well and I said I used to like TDD when it first came out but now I'm constantly being told I'm doing TDD wrong then I'm just giving up on GED you know TDD as far as I'm concerned doesn't work I'm still gonna do some testing but I'm quitting on TDD and of course such a stir that Kent Beck kind of responded saying you know our IP TDD it was kind of sarcastic post which men have been the best choice when Americans are amongst your audience but um he kind of said you know oh well here's all the things I'm not gonna do now I don't have TDD anymore so it's kind of offensive TDD and Martin Fowler actually produced this series of dialogues between mediated them between Ken and DHH talking about to you the DHS went and saw an original version this talk I gave at MDC and was kind of saying yeah I think you and I on the same lines and they came to a pretty similar conclusion as thrusters talk so you might go away if you like the ideas here and go and see Ken and DHH having this dialogue made it by Martin about whatever II think happened but the question is kind of where did it will go wrong right what and wrong for TDD and can we fix it commit can we can we change our our ways um anyone know anyone ever hear of a call to an English footballer called George best no mostly present now it's very very famous in giving a major in their 1970s and the story goes that a bellboy at the hotel enters George's room in the hotel George is lying on the bed naked with a couple of supermodels the bellboy is wheeling in the caviar and champagne that is going to give to George and these naked supermodels on the bed and the bellboy looks down at George says George where did it all go wrong and so treat that sentence in that kind of light right I am a fan of TDD what I want to talk about is you know where did it all go wrong okay so what I want to do really is go back to the beginning and let's go back to the beginning of TDD and I want to explain to you the firmest in my argument is TDD has answers to all the problems that we have been meeting with TDD we have just ignored the fact that basically the original approach to TDT is described by Kent back works later patterns and practices we have loaded onto TDD made many cases a mistake and have led us away from what was originally intended in our mistake so I would recommend who's read this book okay many more if you practice TDD than I read this book who's right so he'd read some other book to learn about TDD who was told how to do TDD by somebody else that worked near them yeah probably more of it okay I would recommend reading this book if you practiced her sister and development you want to understand how it works I recommend reading this book when I began to struggle with TDD I went back to read I read this book again I read it read it originally I went back to read this book again and one of the things I learned was that Kent had an enormous amount of wisdom about TDD having practiced TDD for a large number of years before he read the book and many of the problems I was encountering with TDD Kent had already encountered understood and were discussed in this book and this book of though it seems old covers all sorts of things that mocking a TDD which many people think are they much later in most later developments they happened a lot later in life cycle they're all in him right this book is probably the only wisdom you need but I don't think I understood much which wisdom and so I've been doing TDD for a certain amount of time and I was then able to understand what Kenan was trying to tell me okay I think the most important thing to take away from and understanding of that book is this okay when you are practicing test-driven development do not test template implementation details test behaviors are exploring that sentence more as we go through this talk that is the key thing that people get wrong today so what happens is is a classic modern TDD cycle someone says I'm about to write method on a class I will write a test before write that method and that test will govern that whether that method succeeds or fails and so the trigger to writing a test in TDD practice is essentially adding a method to a class that is the wrong thing that is not the ethos of TDD the trigger in TDD for creating a new test is that you have a requirement you want to implement it is nothing more it is nothing less okay there is something I want the software to do I will write a test to do that okay I want basically the software to add an amount to this customers bank account essentially right I want the software to upload a new file to the users collection of files right that's the that's what drives a test in TDD that's what you are tested writing test for you're not writing test to say the foo method should take the two numbers multiply them and return the result okay and that is an implementation detail there is no requirement you received one problem that's not necessary in a calculator that no requirement you received it gave you that the requirement you receive was something else much higher up right and that is where you write the tests what you want to be doing is focusing on testing the API of your software okay when we talk about the API we're talking care for that in a second but we mean what is the contract your software has with the world what what is it offered to do for people who are basically consuming your software that is the stable idea of your software it will not change that rapidly and you may add that new stuff to it etc but it's a stable requirement you have how you implement that requirement is unstable you may get better ideas over time and you may wish to change it but what your software offers to consumers is the stable contract and that is what you should test we don't necessarily by the way mean by this and actually keep you Jason API right so I'm conscious now that's when I use the word API everyone imagines you know rest HTTP Jason o graph QL whatever I said right what we mean simply by an HTTP API really or by an API really is just the publicly exposed surface area of your module generally that somebody else is concealing so in you know the classical description of a module you know module has basically a set of exports public facing things that other other consumers can call other module but other software can call an internal implementation details that you've hidden away these are these classic notions of information hiding encapsulation right your your modular has a facade something on the outside that essentially represents hides all those details away and it is that external sort of exports that you are interested in testing not the implementation details which tell you how you are implementing that okay what happens is we should get some use cases or a story in and the kind of agile environment and that says here is the requirement I want you to implement here is the story here is the use case here is the thing that your software is supposed to be doing and you write tests to say right I'm going to write test to prove I can do that and generally speaking there are good models first like given when then given the you know given that my account has a hundred pounds in it when I add another hundred pounds to it then I have a total of two hundred pounds right that is a kind of classical requirement trying to implement now I may end up using object to represent accounts and that kind of thing but what I'm doing is saying my requirement is the behavior of my account and a half perhaps when I add or remove things from the system under test is not a class too much TDD practice focuses on essentially writing tests for classes okay the system under test is really the exports for a module its facade when people talk about this phrase unit testing at the time that people were basically coming up with this kind of idea to them classical testing paradigms a unit test was a test of a module right it's kind of a black box where effectively you talk to basically what exposed now there's a certain line between classes and modules where effectively publicans say what a class is a module it's information hiding encapsulation except like I think that and I appreciate that but the definition of unit has become too much fixated on being a class people talk about by selecting that class and I take them across is dependencies right now it leads into all sorts of problems because then you start mocking heavily which leads you in totally callout specified tests where essentially you know all about the internal implementation details of that class through your mocks and how they're called and essentially you've hidden no implementation details so you want to focus in a much higher level you want to say I have some public things that this module does that is what I'm going to test I have some implementation details and I'm not going to test those ok and we will explain how to get there TDD explains exactly how to get there this may sound complicated but there is an easy route to get there ok so obviously you may actually be driving a class because if you're writing say C sharp or Java you can only drive classes but that classmate way may tend to be a facade or command or etcetera some kind of interface to the actual module underneath you don't want to write tests to cover implementation details because of those change you want to write tests for your stable contract which is essentially your exports from your module your API refactoring is the key step which enables you to achieve this goal of separating between things that are implementation details that you don't need to test and things that you do need to test there is a get out clause and they get out Clause says sometimes it's helpful to probe the implementation details are difficult to understand you can do that but the test afterwards again will come back to that so a lot of these ideas I would support it as we go through I want to give a bit of a proxy to Dan - Dan wrote a post about what he called behavior driven development now that's turned into something else really that has it has the same origin point same route this is the root of that when people talk about behavior driven adopted a they mean something else in time what about that later but in his original post Dan said I've often find when I go to basically implement TDD in places people are very confused about happy TDD because of the word test the word test throws them and if I changed that word to behavior drawn up the developing your system using behaviors people do it correctly this insight was very old economist when this war is basically 2500 etc and he's he's saying exactly what really I'm gonna tell you in this talk people misunderstood what Kenan was talking about probably because can you use classical text in terminology like test unit test me I mentioned it's just a couple of times in the book generally the phrase Kent Beck uses developer test right not unit testing developer tests but Dan basically effectively recognized the same problem I'm recognizing it here which is people were driving tests by saying I need to test this method they should have been saying I need I was a behavior in the system and I want to use code to basically prove that that behavior works in the system okay so in case you think that's just a damn thing Kent wasn't talking about this just came back originally so it can talk about behaviors behaviors would demonstrate that confident work will compute report correctly so he's saying the object of TDD is to test behaviors in the system okay here is a classic thing that you are testing add amounts in two different currencies convert the results of given set of exchange rates we are not testing a method on a class we are testing a behavior of the system that we can add two different amounts in two different currencies and then see basically the result in one currency we are multiplying a price per share by number of shares to receive an amount okay the behavior is the requirement these are TDD requirements as described by Kent Beck originally that is what your test should be looking at not I need the method on myclass for exchange rates that's nothing that's not nothing to do at EDD so the idea behind test environment has always been that we are essentially saying what is what should the api of our code look like if i am an external consumer of this code and i come to call it what kind of API would i find useful your testing as much the usability of the api how you interact with it as you are essentially in designing that public facing API is anything else okay so you tell yourself a story about how this API should look if you were a consumer the test becomes the first consumer of your code that essentially says what should this look like and how should it work right that is the objective a test driven development so Kent uses unit tests in a very specific way right and simply for hit when he uses the phrase all he means is that you should better on all your tests together there's one suite without the impact with effect we do that without one test being run impacting the other test the unit of isolation is the test and a lot of mistakes have been made because people believe the unit of isolation is the class under test it is not okay so all these people mocking because they say well you got to have the class isolated when you test it these all have to be mocks you can't interact with anything else you got a mock all the classes dependencies right because otherwise it's not a proper unit test you are wrong the unit VIN permit the unit of isolation is the test not the thing under test so one of the problems is we would you know people were using definitions from classical testing and the thing is essentially unit tests referred to decided over a module right listen wives are confusing phrase because people talked about unit test they were saying take a module so say and.net term is an assembly or something right take that and then essentially test it on its own then an integration test is I've got a couple of modules talking to each other and then essentially a system test is talking all and while just talking to each other so when can they used this phrase unit test what he was really talking about was a module being tested okay it's an unfortunate phrase because people then said well the unit is a class and came up with a hole so our practice which basically has been negative towards RTP practice you may choose to avoid using certain interactions and testing right databases file systems those kind of things right but the reasons Ken gives for that are slightly different for the ones you think it's not about isolation it's about my selection only in the sense that if I touch a database there one test may impact another test because if I add some rows in the first test when I read them in the second test that may be impacted by basically the order they running so I have to make sure that between these two tests I'm isolated from that kind of problem which may mean I choose to use something like an in-memory database unless we tear that down rapidly and provide a fresh one for each test right but it's the isolation of the test that is driving that not the isolation of the code under test same with fascism everything else and the other cut the issue is speed right tests have to run fast otherwise developers don't get fast feedback so really I want my test suite to run in a couple of minutes and it's quite possible if I'm talking to real hard dependencies that becomes hard so I may wish to essentially swap those out for the purpose of a CD speed but those are the reasons for it but there are others if there is no shared fixture problem it's perfectly fine in a unit test to talk to a database or a file system and that happens all the time people are Chemex testing so people telling the you contort it by some unit test they are wrong okay yeah okay focusing on the methods crates tested that are hard to maintain okay because essentially when I look at that test what I see is somebody describing how you interact with a method that's what we get this problem when we come back to our test they're very hard for us to understand because of kind of going well what does his test doing well we've got a method in isolation so it's very hard to understand what it's doing if the test tests of behavior it's very easy to understand what that test is doing because it says this behavior is asserted to be true in the system now that test is red because I've changed another part of my code I can either say well that should still be true or perhaps no that isn't true anymore that behaves been modified now rather than you require which means this behavior has also changed and I've just seen an impact of that behavioral change and when we have implementation details exposed now the words essentially all those things that make up how our API actually works that's when you get this problem effectively of being hard to change particular few use mocks so when I use mocks effectively when I said that's just their class on the test and I know about all the cool set of mocks the problem is when I change something that changes those all the basically assertions break and if I essentially therefore know too much about the implementation details then I've coupled my tests to my implementation and I can't change one without changing the other all right so let's talk about how we get there because the way we do this is really simple and it's red green refactor who and who knows who thinks they understand red green refactor okay great who does red how many of you make sure that essentially okay very few of you who does Green Party most of you who then it always does the refactoring step some okay reflective it's the key thing right the test that doesn't work okay this is important there are no tests for tests I have to demonstrate that my test will fail in the absence of correct implementation right I've always a stumble across this a few times had the problem or essentially had a test that would always pass and so you know essentially until I got that red phase I wouldn't prove anything by writing the right in my code and having it passed again because it's always gonna pass again Green make the test work quickly committing any sins basically necessary in the process this is really important what I'm doing is making the test passed by the quickest process possible okay a good solution here cut and paste code from Stack Overflow right this is where the duct tape type area mcduck wins because you're afraid to do that and he's not do that okay now basically make good code but it's three steps I'll test make it compile unseal it avails make it run reification centuries refactoring okay when you write your foot implement your test and you go to your green phase what you are seeking to do is understand how to solve the problem you want to basically as fast as possible get something that satisfies the behavior I want to add two currencies in different amounts from different from different and I want to basically look at the end result right in one currency what I want to do as quickly as possible is figure out how to do that in my code I just write a good transaction script one line with one line after another don't try and basically put it into lovely classes don't try and essentially put patterns in there just write line after line of code until it works okay and that code can be dodgey if you want to be probably should be your goal is to as fast as possible get that test to go green because you have managed to understand how you will implement the requirements at this point you are trying to determine how you will implement the requirements and you can figure out the answer to that by going green go to stack overflow copy some code right you are explicitly enjoined in this step to write non well-engineered code you want to be the duct tape programmer you want to be that really annoying guy on your team who writes bad code emulate him do what he is doing to get out the door fast you will now be keeping up with him you've added the test but he was automated he's probably having done manually a few times you are moving the same right here's now mr. Blake says for this brief moment speed Trump's design I want to get there as fast as I can okay Kent's point is essentially you can't do two things at once easily you can't both understand the solution to the problem and engineer the code right one of two things will go wrong you will either over engineer your solution beyond watch the test actually requires boy you'll get some kind of analysis paralysis right but the first thing you do to solve the problem with the code okay so when we're getting our clean code you know right okay so we believe in clean code we don't want to have duct tape programmer code oil long I'm we're going to do that the next phase the refactoring step and the produce clean code so if Kent basically near the key drivers duplication right you see duplication you remove that that starts to reengineer your code well and that works there you can add into that I think Fowler Fowler's book refactoring alt about that bit later look for code smells ok look for smells in your code that indicate they're the better ways of doing this and Yoshioka is keys point is if you want to think about using these are design pans this refactoring step is when you identify them because now you have a clear idea what your solution is you can tell whether a pattern is appropriate or essentially whether you're using patterns inappropriately as a solution ok when you refactor and this is the really important part you do not write any new tests refactoring is a process of safe moves that let you essentially change the design of the code they do not change its behavior your behavior is covered by the original test the original test tells me I'm adding two amounts in two different currencies and getting the final result the behave that code them implementing produces that result if I use safe refactoring steps to get doesn't matter how much I changed implementation details I am still covered by my original test code coverage tools help you here because you don't want to introduce for example new conditionals speculative code at this point need to be honest and when you do that you need to have new tests to cover those new behaviors because generally you've got a conditional because you have a new behavior that you're trying to produce but do not write new tests at this point this results in two things one you will write less tests so you will move faster the refactoring step shouldn't take you so long that you four miles behind this duct tape with the programmer right you will keep up in the way that the lean software guides and your managers want you to because you are not saying oh I'm creating a new class here I'm doing extract class because I believe that essentially these things should be Anouk should be a class and my implementation don't write a test for that class right if you have a language to support some visibility for example Java or C in a c-sharp and you've got things like protected internal private cetera public right in c-sharp for example most needs to be internal and never exposed and as such the test should not be coupled to them you should be at liberty to change their implementation whatever you like and no test will fail because no test is coupled to hate on their implementation and this is a key to understanding this right in the refactoring step do not write new tests you're not introducing a couple of classes if you basically keep thinking mmm I need to increase in public class that only smell you may be looking at is that essentially in your solution there is some new thing that is also power I PI ok that will itself be exposed as part of the API have your module in that case that's probably an appropriate time to think about a mock for use in your test and later go and implement that other part your API that you're currently missing right but focus initially on trying to avoid writing these extra tests it says it right dependencies the key problem and software right coupling is worse enemy for you than dry coupling is what kills all software so stronger to decouple your tests from your implementation details focus on your public contract your stable API and leave your implementation details free of tests and avoid heavy mocking this allows you to meet the promise to refactoring you will refactor your code and your tests won't break right I've seen this work since I changed this practice it's been very easy for us to refactor implementation details to figure out want new ways of doing things we changed the whole way we did for example a modeling between of an aggregate without any test breaking because the behavior hadn't changed our choice about how to implement it or changed so test behaviour don't test implementations these mics are are annoying if you wear glasses right okay but des tournelles don't make these puppets a test if you find yourself making things public in order to get it under test by implementation details ask yourself if that genuine is a part of the of the contract of your module if it's not don't it's just implementation detail why did you surface it for testing if you are in dotnet land and you use the assembly attribute internals visible to and list your test assembly so that you can get your internals tested do not do that write your internal should not be visible to the test because they're not under test okay so preserve your presentation hiding have a public API in the internals right this is Fallon's book of refactoring actually came out before Kent's book on TDD and it talks really about code smells and says here are some safe steps to be able to effectively refactor basically your code when you see these smells and one of the key things to understand is you know very explicit okay we are changing implementations it has not public interface anyone ever use the DevExpress tools as opposed to resharper's tools for refactoring so till express what I want at least one e DevExpress have set of tools which basically had a code plug-in this was your studio and these to offer refactoring and don't express his tools and she didn't know some of the guys the workmen were very clear right you cannot refactor a public method on a public class they wouldn't let you do it because that's change that's not refactoring because you don't know the impact of that now later they said ok you can press the button marked unsafe refactoring because everybody else lets you do it and we're being killed in the middle in the marketplace but also because they said well you may say to me the only consumers of this public API within the span of the solution and therefore essentially I understand who all the coolers are and I can then refactor them so if I'm doing a rename I know who I'm going to break but the goal was originally don't do this right don't change a refactoring is not changing your public interface it's changing how you chose to implement that it is a safe small change there are recipes to do them that's why tools automate them and they're safe in the sense that your code is not basically going to CH it's not going to negatively be impacted if you extract a method it's a safe change ok his list of user smells it's not wearing what this talks about but those are the kind of things that you're looking for and those are the things that drive you in your refactoring step to do things like extract a class out of this basically what transaction stripped body has a method out this body right look at basically where you've got feature env whether you're doing some kind of dot syntax etc right and I just you joshiya karaeski in this book said there's a problem with the patterns and the problem with patterns is people are getting pain happy lady sipan's everywhere and start applying them and in many cases what they've done is applied them in the wrong context or made their software over complicated when didn't need them well Joshy Aquarius you said is the ideal step for applying patents is the refactoring step because at this point I know what the solution is a written one it's an awful solution because I was told to make an awful solution and at this point now I can see I can clear up by making a pan I can see that actually this is which is the command pattern I need that here this is the template pan I need that here but I know that now because I've already implemented it once badly and even in CHEM box original book he identifies patterns you may want to refactor too but so this is part of the original TDD is not new stuff okay so what about ports and adapters so this is unfortunately the common way that testing occurs in a lot of organizations before we release the software is a big big wave of manual testing going on everyone's getting into the system running manual scripts et cetera doing some kind of conference releasing right then below that there's some sort of scientist who has who has big Suites of selenium tests that they run against their software here not so bad that's funny of you okay and then we have integration tests and the bot we have a few developer tests right this is a bit of a disaster why well first of all this is really expensive unrepeatable so you really want to automate your way out of that situation this one is very problematic and I'll tell you why um if I change my UI to give it a nice classy new look and feel that's much more you know 2017 rather than 2008 right I may not be changing any other behavior my software whatsoever they do exactly the same thing that did yesterday I've just cleaned up the UI but these tools all break okay but I'm driving them to test the behavior of my system but the tools all break because I changed the way that my widgets work okay so they're very fragile freshman stone they also run really slow quite when you run overnight and then you get the blame game in the morning someone's job in the organization is to determine who is to blame for last night's test failing right if you have find yourself in the situation where you have somebody whose job every morning is to determine who's to blame the test failing you are doing it wrong I know that cuz I've done that and that's wrong okay all the mistakes I'm telling you about right I've made those don't worry I'm not gonna go at you because I think I'm smarter than you I only know this because I've made every single one of these mistakes right so what you want is what's called the testing permit the majority of your code should be tested by your developer tests a small amount of code up here should test your widgets work correctly and in between there's a certain amount of integration testing where the two gets hooked together every bit of a scam in the middle I'll come back to that later okay so this is a hexagonal architecture it's gained popularity recently people at Bob Martin the coordinates the clean architecture simply quit an onion architecture there are various names this architecture various attempts a CO discovery of the same thing all right what happens okay in the middle we essentially have plain old C sharp objects plain old Java objects pent-up Python objects are not here that heard that phrase Popo that's also slang well for the police in the UK so be careful about using that word but yeah but these things are devoid of any technology concerns so don't know how to talk to the database they don't know how to talk to the web they're just basically completely plain on objects without any technology concerns in on the outside what's called the adapter like their data learners have to talk to the outside world it has all the technology concerns so our primary ones over here things like basically an HTTP adapter so something like basically your web framework Web API Django Sinatra effective your Flash matte effects etc or a GUI adapter so like web forms or you know Jagger's would like that right and they talk basically to your domain over here we've basically got a database that your domain used to persist itself from here we've got a sense the idea of things like sending messages everything's that rabbitmq or I'm essentially that kind of thing right or emails in between is what called the port's layer to the port there literally is like a port in an operating system it was a door it's the door which essentially allows once one to be crossed here it's the door that essentially says well my HTTP code he's talked to my domain it would go through this door some kind of facade layer which says we talk to it over here it's saying I'm like my domain code needs to basically persist a database so I have a door that lets me talk databases some kind of repository model happen perhaps now okay you got if you five minutes more and I'll just run through these quickly right apologies for over random static okay so the port here is the ideal point to do York for your tests the test talk to that port layer not to the internals here because the port is how everything communicates with your code and also as everything your code raised like events or cause the database okay so the poor is the point view to make your calls integration tests are really just checking then essentially you can talk to the data credit you're configured correctly on this adapter don't test adapters themselves they use your third-party code and a system test just checks that you can call from the outside in right and that is essentially how you do it okay make two quick points I try very big gears so you may say that's all great in testing the API is fine but I sometimes like TDD to help me understand how something's working and I want to basically drill down using my TDD into the details okay so connect is notionally gears it has how it work its motion I have five gears in fourth gear it's the price you just described to your testing public API and you're getting the basically the full script out and your refactoring that right in fifth gear it's kind of like the implementations very obvious so actually that refactoring step when I write my code rather than write the sinful code I just write the correct answer so it's regular refactoring step be careful here if basically you find that your coverage starts to blow out when you put your tests shift down to fourth because you're probably writing too much speculative code you haven't got tests for if what I find though is that I'm saying I don't know how to go green I'm not really sure how to implement this and I want to fill my way with the aid of tests to probe me a bit more and shift gears down a write some tests to help you do that you could also use things like a rapid beeping rapidly these records and language like Python except for this technique of just feeling your way bit but feel your way but at the end of that process delete the tests the tests help guide you but now they're a burden to somebody else coming along person coming along who wants to basically change the implantation details probably means that your way of doing it they're changing it altogether your tests and they're something they don't understand we're just protecting your implementation details throw them away at the next person coming along write tests if they needed to take the implementation okay ATD the well very quickly Kent Becker Brittany said don't do it because it has T problems customers are not interested and it's very expensive to do right he later 7120 had a book about ATP in this series maybe I was wrong maybe actually you need this because programmer tests are problem they don't focus on the gist of the system James Shaw who wrote fit said I he was only guys that wrote one of these tools says I don't do it anymore they said the reason in fact over the years that customers essentially don't care and there are significant maintenance burden rights all these tools that fit gherkin that that kind of thing right he just says actually if I have customers again that help developers drive the developer tests so the unit tests are informed by the developers talking to the customer and write the appropriate unit tests over time I used to believe in these test days to think that was worth writing at you know fit and gherkin test because I think you can respectfully test because I thought it helped keep developers honest we know what done done was but over time I've come around to realize that probably what we were solving was the problem of how we're doing our unit testing because our unit testing was focusing methods on classes we had nothing that told us about behaviors but we actually to do a shift our TDD practice through about behaviors and then we can drop a TDD altogether just write developer tests in the same language using to implement and drop these horrible translation layer between natural language and your code base Avram development I mentioned briefly the Dan basically the craziest Engel had this original post which basically it describes testing tree about behaviour it is now a full-scale agile methodology it's worth it being you may be interested in that but this talk is not about behavior and development as a methodology right it's taking that original kernel idea that Dan had a saying test behaviors don't test methods and classes mocks briefly mocks are useful when a resource is expensive to create and represents a shared fixed a problem but the problem with mock objects essentially is people have used them to isolate classes don't do that and especially don't do this thing where effectively you say I'm going to make sure junior developers have done the right thing by by mocking I forced them to use mocks so I can see how they implemented the method it just couples your test to your software means you can't change it it's never worth it they also specified software generally speaking IOC containers are overused Chinese move live as possible only use them because your framework demands that you actually do it because they don't understand how to create objects that you have if your framework was good it would actually ask you to give it factories not I did not an IRC container and you might implement your framework have fought in terms and I see container if you find yourself implementing an IOC registration in your test something has gone horribly wrong okay bit like ORM as we overused IOC containers please avoid that okay right quick summary reason tested behavior and basically because we as a new behavior my dirty code to get green and refactor no need to test three factors internals and privates they're open sets against tests right on a port and second architecture add integration tests only really to extent you're covering basically our ports implemented and don't mock internals processor adapters are not one little bit missing asset defended cup words okay I rather had type of questions I'm sorry III gonna let you'll go please come up to the front if you want to ask a question at the end I'll come and find me during the conference I'll have to talk about the stuff you can see this talk online versions we've given the place like MDC so you want to share with your colleagues you can you can go and dig out the video and I think these guys are pretty bidding it too so you can spread the free edge with your colleagues it's worth going looking that conversation between Kent Beck and DHH need to be Martin Fowler as well for a similar conversation about how it's all gone wrong but thanks very much thank you [Applause]
Info
Channel: DevTernity Conference
Views: 450,787
Rating: undefined out of 5
Keywords: devternity, better testing, bdd, clean code, refactoring
Id: EZ05e7EMOLM
Channel Id: undefined
Length: 63min 55sec (3835 seconds)
Published: Wed Dec 20 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.