What flavor of TDD do you practice? In this episode we talk about Classical vs Mockist TDD, Detroit vs London, Static vs Behavior, Inside Out, Outside In, Double Loop TDD, BDD, FDD, Tracer Bullets, Rules of TDD, Team Structure, Lean TDD and so much more.

Transcript for episode 162 of the Test & Code Podcast

This transcript starts as an auto generated transcript.
PRs welcome if you want to help fix any errors.

00:00:00 Welcome to Test and Code. Today we’re going to talk about the flavors of test driven development. There’s frequently times where I get asked if what my thoughts are about test driven development, and the next question I have for somebody is what flavor of test driven development are you talking about? To which I usually get a blank stare. So today we’re going to talk about some of the different types of test driven development there are out in the world, so that when we talk about it, we can talk about it coherently to each other. The punchline, of course, I’m waiting for the end. So please listen to the end and we’re going to talk about lean tester and development at the end. So stick around.

00:00:50 Welcome to Testing Code.

00:01:02 Thank you, PyCharm for sponsoring this episode. You probably know that I love the user interface for tests that PyCharm provides. I just really like running tests from PyCharm. It’s really easy. I’m also playing with Python 310 lately, and I’m pretty excited about both. The pattern matching feature. It is like Switch statement steroids with pattern matching. I’m pretty excited about that. The new Pipe 21 two version supports that out of the box. That’s pretty cool. Another thing I’m excited about is the Union types. The new Python addition supports those, and it helps you with the code completion. So definitely check out PyCharm, go to testingco. Compaarm and you get four months of the Pro Edition free.

00:01:52 So let’s jump in. Let’s talk about test driven development.

00:01:56 There’s actually quite a few different kinds of test driven development, and one of the reasons why I think I put off talking about it too much in this podcast is because of the different kinds, and I just really didn’t want to get into the arguments with people.

00:02:10 However, I think that there is a hole in how we’re talking about TDD. And so at the end I’m going to talk about a variant that I think of as lean tester and development, mostly just because I’m lacking a better name. But we’ll talk about that later.

00:02:26 I want to talk about a lot of the common types of test driven development you’ll find in the world. So if you look up on Wikipedia and actually I’m not even going to drop a link, but I’ve got links to other things.

00:02:39 For test driven development, there’s basically a cycle of developing code and developing tests at the same time. And so TDD is a very agile sort of a thing.

00:02:51 I’m not using Agile in the capital A. It’s really agile in the lower case a is that it helps us move quickly with the developing software. So on Wikipedia it talks about the cycle is adding a test to your code and then running all the tests and all the tests except for the new test should fail, but the new one will fail. And then you write some code to make your new test pass and then you repeat that, but then you also do some refactoring so your refactor is needed.

00:03:27 And we often say red green refactor because we only want to refactor when we have passing tests so we can refactor and keep the test passing. So we want to make sure if you’re changing test code and source code at the same time you don’t know what went wrong. So we’d like to have the test working before we refactor and refactor into clean things. So refactor means things like moving code to where it logically belongs, removing duplicate code, self naming, changing names, splitting methods if we need to all sorts of refactoring techniques to make the code. There are all sorts of techniques, but really what I like to say refactoring is making the code what you are proud of. So I like the refactor stage. It’s my favorite because that’s where I get to make the code. Something I’m proud of that I can go at the end of the day I’m like, yeah, this is neat, this is nice code that I wrote and it works.

00:04:28 So red green refactor. A lot of the things though that people leave out is the thinking part. So before TDD XP Extreme programming sort of popularized test driven development, and before test driven development there was test first programming. And when people taught test first programming it was a little bit more about thinking about things. And I think we’re losing the thinking about things. In a lot of the modern test driven development teaching, we say things like write the simplest tests you can or write simple tests, but there’s complex behavior out there. Some tests are actually not that simple to think about and write. So thinking first is good. So I’ll replace the red greenery factor sort of thing with think about the behavior that you want, write a test that reflects that behavior, write code to make sure that test pass and then refactor until you’re proud of the code and then start over. I like that. So what are the different variants? There’s lots of different ways you can approach test driven development.

00:05:39 One of the classic dichotomies is classical versus Moccas. So classical is where Kent Beck and Martin Fowler come from often. And there’s a whole bunch of other mockists that are different. So classical is really just without mocks for the most part. So you’re writing tests against source code that doesn’t need mocks, which means you’re writing tests against and then you write enough source code at all levels, at whatever level you need to make it work. So your tests are at the unit level or at the higher level or whatever.

00:06:17 But you do have to write all of the code to make it work.

00:06:21 Mockists are more talking about just using mocks.

00:06:29 I think it’s isolating more. So the function in question, if it calls other functions, I might mock out those functions so that I don’t test those functions also or classes. If I’ve got helper classes, whereas class school just if it’s an entry point and it says to do something, I’m testing that it did something.

00:06:51 This is also commonly called as Chicago and London. So classical is Chicago, Moccas is London. And that’s really just because the wait, I think it’s Detroit. Anyway, who cares about places?

00:07:07 But the other bit is state versus behavior, which I don’t quite agree with either, but you’ll see references to that. So classical is thinking about state. So if I say increased speed function, the outcome of that is the cars going faster and the speedomers registering faster speed or something.

00:07:34 There’s side effects. Either there’s outcome of the function or there’s side effects that I’m testing, whereas the mock is there’ll be no side effects because I’m really kind of isolating the state with mocks.

00:07:46 There’s also talk about this is all the same thing. Let’s talk about inside out versus outside in. So there’s an assumption by the mockists that their way you can do it from top to bottom. So if I write the API first, I don’t have the lower layers so I can’t use those, so I have to Mark those out so that’s outside in, whereas the classical would be I’m going to write the unit test for the small thing, all the little pieces first and then build up the top thing. I don’t think that’s really true because we’ll talk about tracer bullet testing a little bit later anyway. I think a lot of these like classical versus Mockus or inside out versus outside in are really just false dichotomies because there’s good ways to approach different problems and sometimes some of these work and sometimes they don’t.

00:08:42 But I guess let’s talk about the level of testing and how much is implemented a little bit.

00:08:51 So there is a talk of like what size of the unit. So the tests in Test Driven Element are often thought of as unit tests. And that’s what a lot of the early documentation was around. Xp was talking about unit tests, but maybe I’m wrong, but when I read it, I was reading it as developer tests. Basically it’s test the health of the developer. And they’re called unit test because the test frameworks were using were called unit test, unit test frameworks and that’s it.

00:09:28 They can be large things. I can use a, I can call an API and I can do a system test from a unit test framework. That’s fine. Maybe I’m wrong, but the system test idea of writing not necessarily through the user interface, but maybe through an API or at least a high level entry point. That’s where behavior driven development comes in with BDD and then a tracer bullet kind of approach of saying let’s do one feature at a time instead of doing the whole thing. Like let’s do one feature at a time and complete the whole feature through the whole system. That would be feature driven development, which didn’t really catch on. I’m not sure why, or maybe it did, and just I wasn’t exposed to it.

00:10:16 What I was exposed to was Pragmatic Programmer, and the Pragmatic Programmer book talked about tracer bullet implementation, and that really made sense to me. So you can do the level of tests, you can do it at the top level if you can get access to it. And then the implementation for a feature for a little tiny piece of it can be implemented through all the layers down below. And in some of those cases, so that’s a high level test. But in some of those cases, to implement some of those lower level functions, you’ll want to have more lower level tests to test whatever piece that you need. And that’s fine. You’re adding tests.

00:11:05 We’ll talk about some rules in a second.

00:11:08 I’m okay with breaking rules because rules are meant to be broken.

00:11:12 So a top level test is sometimes considered an acceptance test because it’s testing the user disposable behavior of a system.

00:11:25 And a unit test is like testing a function or testing whatever the developer sees, or testing a class, or testing an API or a subsystem.

00:11:34 All those are some and then integrate.

00:11:38 There’s no accepted truth of what all these mean for anything but integration test is absolutely the worst definition anywhere, and I don’t even know what the definition is. But it’s somewhere between unit test and acceptance test.

00:11:52 I don’t know.

00:11:56 Let’s say I’ve got.

00:11:59 Yeah, let’s just jump into the rules, because that’s an interesting discussion.

00:12:06 There really are no rules for test driven development. However, Robert Martin was one of the not to be confused with Martin Fowler. Robert Martin came up with I think it was him that came up with it, came up with these rules of TDD. And the rules were write production code only to pass a failing unit test and write no more than of a unit test that is sufficient to fail, and write no more production code that is necessary to pass one failing test. You’re taking little tiny incremental steps.

00:12:44 Okay, maybe that works for some people. It doesn’t work for me, but let’s just pick it apart for the fun of it. So I’m supposed to never write any production code unless I have a failing test?

00:12:56 Well, what about refactoring? Refactoring is all about writing production code when I have all green tests and keeping them green.

00:13:04 So I’ve broken that one already.

00:13:07 How about no more of a test that is sufficient to fail? Well, I actually just really want to solidify and codify a user behavior at the top level that is expected, and I want to codify that as a test.

00:13:29 I’m not going to just go halfway through, even if I’m on a role. I might write two or three tests. Why not?

00:13:37 I don’t see the problem there. And then write no more production code. That is necessary to pass that one failing unit test. Actually, that one’s a pretty decent one, and that’s therefore trying to keep you from just over coding.

00:13:56 If you think you might want to do more, just your tests are passing. What are you doing here?

00:14:04 Maybe you’re gone on to the refactor stage, but at least admit it.

00:14:10 So I don’t think there’s really rules around those. I think they’re silly to talk about rules of TDD, but the size of the unit and stuff, whatever works for you. But there is this notion of like, okay, well, what if I’m writing the developer level test? The unit tests, but I’m not really writing the acceptance test. I’ve got some other person like a team of people doing the acceptance level test, the system test for the system. And I’m not even dealing with the system. I’m just dealing with a little component on my own. And I think that’s fine.

00:14:47 But you can think of like, let’s say your little component. Think of that and test against that testing of the API of your component. I really doubt that you’re only responsible for one function. That’ll be a weird job.

00:15:01 But there is this notion of a double loop test driven development and that’s the idea around that is I write in a system level test, an acceptance test, or maybe somebody else does a test, it fails. So I need to write some code. But instead of just writing some code, I write a unit test and then I jump into the TDD cycle. So I do behavior driven development for the acceptance test.

00:15:29 Test development for the developer test and code got a separation of people.

00:15:35 Maybe the test team is doing the acceptance test and the developers are doing the unit test and code all go out for beer on the Friday night and everything, but if that works for you, great, whatever. But there’s still duplication there.

00:15:55 Anyway, I have a problem with if the acceptance test is enough to test the system, why do you need an extra unit test? But you might need lots of extra unit tests to test little tiny pieces. That’s fine, but if you only need one, what’s the point? You already have the exceptions. Test.

00:16:14 I want to talk about the goals of test driven development a little bit.

00:16:18 The goal for me is to work fast. So I really want to have the tests aid in developing code faster than I could without the tests. And I want to be able to change my mind quickly. So I like the refactor part.

00:16:36 And so refactor whenever I want to and play with the code and write stuff really quickly and be really satisfied that my code satisfies the user requirements and I can sleep at night and nobody’s going to bug me because I broke something.

00:16:54 So making sure new code doesn’t break old code, that’s a good goal. Making sure that I can refactor easily.

00:17:02 That’s an interesting goal, because that means that if I want to meet that, I cannot write a whole bunch of tests that test the implementation. I need to test behavior on implementation.

00:17:13 So that kind of throws out a lot of the mock stuff. I’m totally on board with mocking external stuff. So if you’ve got an external system that’s not even controlled by your company or your group and you want to mock that, you’re not going to refactor that out. So as long as you’re refactoring in the code that you have control over. Great.

00:17:35 So team structure matters because I didn’t want to talk about team structure a little bit. What if I don’t have an external test team? I’ve just got developers. And what if I don’t have developers? I just have me.

00:17:50 Let’s say I’m working on an open source project and it’s just me or just a couple of people, a small startup. There’s only developers. Why would you hire a test team if you’re just a bunch of developers coming something new, in which case you really don’t want to be wasting time. And the whole Do Micro Increments and red green refactor like 17 times a minute seems excessive and especially if you’re going to throw away code. I don’t want to throw away code. Oh, the throwaway code thing. I do want to talk about that a little bit. There is an image which I’m not going to link to, but it probably should for test driven development.

00:18:33 That is how traditional software is developed. And it shows like the development of a car. It shows like wheels and then more of the car. And then finally at the end you’ve got car. And the TDD approach is you start out with skateboard and then you have a scooter and then a bicycle and then a car. And I just don’t get the analogy. I think the analogy is you always have working code. I like that part. But if I’m building the next SpaceX and I want to build a rocket, I’m not going to start with a little Estees rocket or a slingshot that’s just I’m going to go for the rocket. Just saying. Anyway, I did want to talk about lean, test driven development. So Lean, this isn’t a thing that’s out there anywhere, but it needs to be a thing. And the idea is let’s not do the outside in or inside out. Let’s do test driven development with the end in mind. So let’s say at the end when we’re delivering code, I want a full suite of acceptance tests that completely test the behavior of the system that I expect that is expected from the user’s perspective. And then I have enough unit tests to help speed up development of internal components, of course.

00:19:59 What does that ratio look like? I don’t know. It’s different for every application. It might be a whole bunch of acceptance test and code. Very many unit tests. It might be just a handful of acceptance tests and a whole bunch of unit tests developed depending on what sort of system you have in mind. I don’t care about the pyramid. I just care about enough to have confidence in the code and then we’re going to implement them with tracer bullets. We’re going to say we don’t know what the system is going to look like, but we know that for this feature we’re going to do this and we’re going to write a test for that and then we’re going to write a lower level test if we need it. But we don’t have to. We’re going to focus in and in the end and yes, we’re going to throw away some tests. Yes, we’re going to throw away some code. We’re going to refactor a lot. We’re going to refactor both code and tests. But I’m never going to get to the point where I’m going to say I don’t want to refactor because I don’t want to touch the test.

00:20:50 That would be terrible.

00:20:53 That’s like the old waterfall thing is I don’t want to refactor the code because then I want to change the design document. How ludicrous is that? We don’t want that. We don’t want to avoid test refactoring and when it’s the right thing to do because we have too many stupid unit tests, I don’t want that anyway. So I’m going to have to flush out lean TDD. I’m going to do that kind of in the open over the next several years, probably. And hopefully other people will help out with that.

00:21:23 I probably didn’t cover all of your questions about test driven development, so yeah, let me know. There’s a contact form I’m on Twitter at Brian Hawkins and there’s a contact form at testing Code.com.

00:21:36 Please send me your questions around test driven development. If I don’t know the answer or don’t have an opinion about the right answer, I’ll find somebody that has an opinion or maybe the right answer anyway.

00:21:50 Yeah, I think that’s it. Thanks a lot.

00:21:59 Thank you, PyCharm for sponsoring this episode. Please check them out at testandcode.com, PyCharm it’s wonderful to have them as a sponsor and thank you to all of my wonderful Patreon supporters. Join them at testandcode.com. Support if you’d like to sponsor an episode of test and code, you can also find information about that@Test And Code.com support as well. Those links, as well as links to a whole bunch of articles that talk about different test driven development variants are at DC Code.com.

00:22:31 That’s all for now. Now go out and test something.