 Fyrtu y blaen, ond yna'r teimlo i risio eu cyfnodr, yn gallun i'w cwestiwn. Mae bydd sicrhau y gallwn anodd ar exertio i'r hyn. Mae fawr yn oni'r teimlo i'w clwlethau. Fe oeddwn i'w cwestiynau bod yn gallu hanesol gyrfaen na gennym. Mae wedi'i cyffredinol i'r teimlo i amdannu cyflwydd. a a i'n hyffordd ar ôl i'r ymu hefyd yn oedd y dyma yn y perthyn. I thathaeth angen. Yna yna hefyd yn gallu ein bod ni'n bisbl yma o'r cyffredinol i'w têl hwnnw. Roedd yw ni'n gweithio i'r perthyn, yw yma wedi bod yn yn fawr yn gweithio i'ch neud. Roedd eば, yn gallu yma o bwyl hwnnw bwyl bwyl Aberaidd, Cucumbo, gan y rhaod? Yn ysbyt. Pa, rwy'n gweith. Rhaeddai yna wedi'i ddud! The extension of TDD, TDD lead-those up nicely onto TDD test driven development. Some people don't have a full understanding of what that means. I suspect most of the people in the room do but specifically here we're talking about not just covering your code with tests, but actually writing the tests before you write the code. a'r prysgau yn ymhelydd yng ngyraed. Ymweld yn ymdweithio'r test, yn ddychud ymddangod, sy'n ddigon o'r cymdeit o'r cod, a'r prysgau yn ymdweithio'r cyfweld. Dydyn ni'n cael ei ddechrau'r ddweud sy'n gweithio ymdweithio'r hyd yn ymddangos. A ddweud o'r llambol. Ymdweithio'n ddwy'r ddwy'r testau sy'n ddwy'r cyfweld ymdweithio. Oni ddweud o'i ddweithio'r cyfweld, mae'n ddweud o sylwg o'r perthynatau ar gyfer cyhoeddiadau yn ddeithas, ond yw a'r cyhoeddiadau yn cael ei wneud am y prosiectau yn cymryd i'r ysgawr, a'r prosiectau o'r prosiectau yn gallu prysail. A'r prosiectau yn cael ei bod yn ddylch yn cael eu llif, a'r prosiectau yn eu ddweud. Dwi'n ddim yn cael eu prosiectau, a'r prosiectau yn cael eu ddweud, Sometimes, very occasionally, the project runs over budget and what's the first thing to get pushed off at the end. It's the testing and it's the documentation. So quite often what happens is if you don't write the tests first, they don't get written at all, particularly with time pressures and things like that around a project. So it pays to write those tests first and that becomes a discipline. Once you've actually started doing that, it can be, it certainly was for me, a real kind of life-changing experience with your work. I've got much more confidence in the code that I write now, particularly changing major components, major areas of the code. There's a certain safety net there. Why isn't the TDD enough on its own? Why do we have this extra step? There's one, there were two things in that final section of project development, the testing and the documentation. Particularly if you're taking an agile approach to your development, by that I mean you're not doing a detailed upfront spec. You're discussing the spec in detail for each feature as it comes into the work log. Documentation can often get missed out of that process. Particularly documentation from the customer standpoint. Even if it does happen, if you're writing code and it's changing a lot, there's nothing stopping that documentation drifting from what the actual code's doing. So quite often the docs end up not really being an accurate representation of what you've built. So, I'm sorry that's drifting off the edge. We do have a certain level when you do TDD. There is some documentation there in your test code. I can look at this and I can understand and perhaps even people who aren't Ruby and Rails developers could probably in a couple of minutes understand what's happening there in that test. How many people think that all of their customers would understand that? Nobody that I can see. So, I've got a couple of customers who could, but most of them you're not going to be able to show them this and say, well, this is what we discussed and, you know, reams and reams pages of this kind of code. You can't interact with the customer who's the expert in their field of the product that you're trying to build. That's when BDD comes in. It's applying the same kind of principles, but instead of writing a testing code, you're writing the expected behaviour in your natural native language. That's something that you and your customer probably have in common and something that you can actually discuss. You write that behaviour, it fails because you haven't implemented that behaviour yet and then you write enough code to make it pass and then you repeat that process the same as you do with TDD. Now, here's an example of a part of a BDD feature. Probably most of the customers that you deal with are going to be able to understand this. I'll just leave it up there for a minute for you to look at, you know, if the customer can't understand that, you might need to walk away from the job at that point. It's kind of a bridging point between you and your customer into their domain, your domain into their domain and a common point of understanding for you. The actual implementation of this, generally each feature which might be represented by say a story card or something that's really got a single line description of that particular feature. So in this case I want to manage articles on a website. So that's all you've written down when you've actually been doing the overall plan, manage articles and you're on to the next thing. You implement a set of scenarios in one file per feature, generally. Usually those files have this front matter. This is not executed or evaluated in any way. It's a kind of formal standard structure to lay out. It's useful as an argument point if the feature that you're about to build for the customer has no value because what you're essentially doing is asking your customer, well, what's the, you know, in order to do what are we about to implement this feature? And if the customer can't answer that question, you know, why are we about to build this? Then potentially, you know, you can say to them, well, you might need to think about whether you really do need that or maybe that's something you think you need if you can't describe a business value for it. So after that front matter usually there's a set of scenarios. Now these are actually the executed code, essentially, of these tests. They usually follow this format given something, some precondition. When something I do something or some interaction happens, then we get an expected result. So the outside-in part of the title of this talk is really, I'm going to show now how you'd implement a very small part of a Rails application. Just starting with this, an empty Rails app, which is what I've built to do this presentation, and this one feature file. And I have this one scenario here where this is what we've agreed with the customer is going to happen. Obviously they'll always be more complicated than this, but you should get the basic concepts here. So I write this feature file in plain text, and I use the rake tool, which anybody who's worked with Rails is going to be familiar with, to run this, how's that read? That's good, that's visible, to run this. And immediately I've got a failure. This is using Cucumber. There are other tools available to do BDD. I think certainly in the Ruby world, Cucumber is the most popular. And you'll see other talks doing all kinds of crazy stuff with Cucumber here at the conference. So, helpfully here as well, Cucumber at the bottom there, is actually telling me the code that I need to write. There's a lot of built-in behaviour in Cucumber that comes from the core and from Rails itself and various plugins to Rails. But you will have to write certain bits of code to tell it when you have this natural language sentence. How do I map that to a test? So here, it doesn't know how to map this to a test. So this is the first line one we're failing on. The first piece of code I have to write is to explain to it how to make that precondition. I want two articles to exist with these titles. So I've just used a regex here, split up the titles on comments, and I'm going to create two instances of an article from those. So I run again. Instead of getting the undefined step definition there, I get a failure. So it knows what I'm talking about now, but uninitialised constant article. I don't know what an article is. It's a completely empty app at the moment. There's no model. So, okay, well, I need an article model then. So simply generate an article. It's got a title as a stream and body text, and I'll bring my database up so that it's got those database fields. Okay, awesome. We've got one green dot now. We've passed that first line. I'm on to the next one. So when I go to the list of articles, the web-runner component here knows when I say, when I go to, it understands what I mean. It knows I want to go to a URL, but it doesn't know how to map the list of articles to a path. So the first thing I'll do is, in one of the support files for Cucumber, I'll just create, and this usually has a big long switch statement with all of your different mappings. You can use regex in there, and the home page one comes by default. So most applications, that's going to be slash. And I'll just map the list of articles to slash articles. Go on. Still failing on step two. There's no route in my application to match slash articles. Okay. So I need to put in the main routing config to create all of the restful actions, to map, get and put and post to slash articles for that particular model. And I'll just create a stub controller, because bear in mind I'm just trying to make this pass at this point. I'm not getting ahead of myself here. I'm just going to try and make it pass as quickly as possible. So I create that action. We're still failing then when I run again. Missing a template file. Okay. So I'll go and create that template file. I don't care about the content at the moment, so I'll just stick that in the default layout. Okay. Two green dots and another failed step. So we're getting pretty close now. The I should see is another part of the aspect of matches that you get by default, which is just going to look at the actual HTML content and try and find those strings. So I haven't seen pizza within the content of my article, which I was expecting to see. Okay. So I now need to just iterate over all of the articles in my template and create a list item with the article title in. And then another failure. Okay. This time that variable at articles is undefined. So okay. Next step, define that. I'm just going to load all of the articles in the database into that variable. Everything's green. So at that point, the features complete. And essentially the good thing here is that Cucumber has done a lot of guiding for us. Some cases actually told me what to write where. It's quite useful, particularly those matching those step definitions. Problems with this approach. Cucumber above and beyond the general slowness of the Rails testing environment itself is even slower. There's a few things you can do to combat that. You can attach tags to the tests. One of the built-in tags is WIP work in progress. So if you have that tag on things, you can just run the tests for the stuff that you're working on now. And then when you've completed that set, you run the whole suite again to make sure you haven't broken something elsewhere and then you're on to the next thing. It's best not to try and map all of your possible error conditions and edge cases using Cucumber. Most people recommend just the happy path behaviour, what you expect to happen when everybody fills out every field correctly on the web forms, and the world's great. JavaScript needs a different approach. I'm actually not sure of the best approach at the moment. There's a few different techniques to test JavaScript, but the way the actual web fetching works within Cucumber, you can't do the JavaScript using default. So if you've got a very heavy JavaScript app, that's going to be an extra hurdle. The last thing is that unlike in the normal Rails tests, you get some access to the internals of the controller layer, so you can do things in your test code like log a user in, which is really, really useful, because generally you'll have one test that tests a user being logged out and a whole stack of tests for an admin user logged in and a regular user logged in. In Cucumber, without doing a lot of hacking, you've got to log the user in manually for every single test, so that obviously adds to all of that overhead. A summary for me, the value of these tools is that you've got documentation in a human readable format that's executable and verifiable that your app says or does what your documentation says it does. I think that's probably a concept that's going to spread beyond Rails into a lot of development frameworks. I think people in the Python community are starting to work with this stuff a lot, and I think it's a concept that most people can kind of see some value in. The Cucumber is a replacement for the Rails integration tests, but not your functional unit tests, as in testing your controllers and your actual model layer. We'd always go above and beyond what I just showed there. At certain points, we'd actually test the controller with error conditions and things, and we'd test the model with unit tests. Really, this is just that happy path testing that you want to do. You still want to test against all your edge cases. Lastly, as I said earlier, it's a common ground and a meeting point for you to discuss and document the project with your customer. Thanks for listening, everyone. Questions now. Steve, there's a question behind you just up there. Just the worst case scenario. Can you make a mistake in your regular expressions and it picks up the wrong thing in your implementings? A wonky regular expression? I think probably the behaviour would be undefined, usually. Is it easy to pick that up? I guess there could be a lot of varying different results from that. Hopefully nothing made you would happen, but we'll have an experiment later and see what actually comes out. Seeing as that's driving your whole development instead of testing what you thought was true, it's telling you what's true. One of the nice things is that, generally, you'll be writing the strings and things that the regular expression is receiving. Hopefully you won't be putting weird characters and stuff in there to mess things up. There's definitely that possibility for error there. Any other questions? The elephant in the room? Why aren't you using BDD now? That's a really, really good question. The two projects that I was going to be working on haven't actually come up yet, and the other stuff I'm working on is probably got enough and complex enough tests for me not to start down that road at this point, but I certainly will be in the next couple of months, I think. Every faux natural language system I've ever used has sucked terribly, because they're invariably not natural language. Do you find yourself having to keep in mind that this is just some strings that are getting pattern-ratched, or do you find yourself trying to write sentences that invariably fail? You're going to get the biggest gains if you actually go with what you know is implemented already, so obviously you are already constraining your language to a point there where I know that I want to write I should see here, and I should see this, and I should see that. The value is not necessarily, I think, just the fact that it's natural language. To me, I can see the biggest value in the fact that your customer can understand it, even if it's a subset of their native language. They can understand what you're writing down. There might be codified ways that you could make it readable as well, but generally the codified testing gets too complicated for most people to understand, I think. Anyone else? If there are no more questions, everybody, please thank Malcolm.