 My name is Adam Cuppey. I am a principal at Zeal. We are a Rails consultancy. We specialize in test-driven development. Not anymore. And we are kind of an agile consultancy as well. So today the focus of the talk is to talk about our spec design pattern. So just to clarify the expectation for today so that again it's clear is this is not going to be a workshop on what you should be testing. Okay, so this is, I know, get out. I'm just kidding. Okay, although I'm going to cover a few of those things, this workshop is specifically surrounding how you should structure a test. Okay, and the primary goals of structuring the test are so that it can be extendable, that it's relatively dry, and that you're using the you're using the conventions that our spec has established for you to use. Most people fit inside this, or when they're writing their tests, they only use the handful of things, right? They use described blocks. Well, they have to do at least that, you know, and then beyond that point they probably use it. Many of you probably are familiar with let or even before and after blocks, right? Oh, but before we get going I want to just tell you guys of this. So our consultancy puts on a workshop and training. Last year we had Kent Beck, who is one of the first signatories of the Agile Manifesto. He helps co-organize the event with us. And then last year we also had Ryan Bates facilitate the workshop with us as well. Granity's on hiatus now, but very cool. So this is a workshop where if you want to learn anything more, this is going to be the best place to do it. If you go to roguerails.com and you add your email address in, that's all you got to do. We're going to do a very, very smoke and sweet discount for everybody here at Rails.com. But being that that's the primary website, it's going to go away and go down. So it's just roguerails.com. Very well worth it. I highly encourage it because I want your money. Yeah, I would be crazy. Southern Oregon. Yeah, beautiful Southern Oregon. Yeah, you're, see, here's how you want to do it. Let me just tell you, okay, just between you, me and the wall and the interwebs. You're going to show up a few days early. You're going to go hiking in the fields. You're going to go down, ride a river of some kind. You're going to have a good time. You're going to come down, learn a little bit of code and go home and say you learned something. Okay, that's how it's going to go down. Okay, so again, this is about design patterns. So what we're going to print, the way this is going to be structured is that I'm going to talk through, kind of illustrate what a pattern is, okay, in terms of an RSpec design pattern. And then we're going to, I'm going to show you a few examples and then I'm going to actually walk through doing implementing the pattern. Okay, again, this is a live coding workshop. So even though I've got a handful of slides to show, they're not going to be the primary use. If you have questions, what I'm going to ask that you do is just simply like hold on to it and then I'm going to have an opportunity where I'm like, okay, do you have any questions about this? Because what we have found in the past is that a lot of either questions get answered or what happens is there's a time and a place where, you know, you're kind of like working as a collective. Okay, another thing that's very much going to happen during this is you're going to buddy up. We actually implement pair programming a majority of the time. So we're big fans of kind of the collective learning process. If you're not comfortable with that, I got men. So again, kind of get used to the idea, right? Are there any preliminary questions? Very good. So what I first want to do is I want to gauge and get a sense of where everybody is and there are spec and or testing knowledge. Okay, so on a scale from zero to five, zero being I have never written a test before. So I am an absolute newbie to five being I could be standing here. That's right. I put myself in the five category. Give me a sense. I want you to raise your hand if you would consider yourself a zero like you've never written a test before. It's okay. It's cool. Okay, never written a test for. Okay, you're a one. You've written a couple of tests, but you really don't have a strong sense for the structure of them. You get the convention. Okay, give me a two. You've maybe written them on an app of yourself, you know, for yourself, but you know, you don't know what a good practice is. You just it's ad hoc. Okay, how about a three? Halfway there, you'd consider yourself, you know, you're not a newbie anymore. You have a strong sense of the components. How about a four? Very good. Hello, nemesis. Okay, and and give me a five. Excellent. Let's fight in the corner. Very good. Okay, so, okay, so this is going to be good for everybody. Now, again, how this is going to work is I am going to cover some some of the basic components of it. But at the end of the day, trust me, we're going to get to some components that are a little bit more comprehensive. Wow. Okay, so let's take a real quick break here. Unfortunately, all of those of you who just arrived, you did not appear in the group selfie, but that's okay. We're going to do another one. Exactly. Thank you very much. I will be tattooing it onto my arm when we're done. Okay, very good. So again, the focus of this is to talk specifically to how we write tests, not what we are testing, although I'm going to hit on a couple of those points because they kind of go hand in hand a little bit. I would highly recommend I'm a big fan of Gary Bernhardt and Sandy Metz who speak a lot to what to what to be testing. So if you are looking for more information on that, those are two resources that I highly encourage because they do a really phenomenal job at identifying what matters. So again, so ranging from experience, basically from zero to five, five being very, you know, highly competent. This is, you know, old hat for me, I get how this aspect and structure works. I'm going to be, I'm going to be tackling pretty much the entire range. But we're primarily going to be focusing on the two to five portion of it. Actually, probably the two to four, when we get into the five, if we have enough time, I'll go through some of like the really kind of really strong patterns that you can utilize to really drive your tests. But we'll get there when we get there. Okay. So the first thing that I want to talk to is controlling your values with lat. Now, again, we're like on the two ish range here. Okay. So the core some of the core functionality at our spec has to offer is that, you know, we can easily run into problems where we have got like, here's an example test that we're going to start with, right? And we're going to work from this baseline example. Okay, so just simply to put it to put some context into it. So this here is just, you know, a simple user model, right? We've got a just basic Rails application, user model, you know, we're not using device or anything like that, you know, I don't want to get too complex here, you know, don't criticize the way in which I wrote this code. This is just, you know, a basic simple example, right? You know, so as you can see, we've got like 26 lines of code total, you know, not a whole lot, we're extending from active record base, we're using a couple of validators, you know, we have some, you know, just kind of simple functionality functionality in here to, you know, to do just some basic action authentication, you know, if you notice, we've got a first name, a middle name and a last name. And then down online 19, we've got a new method where we're actually going to concatenate them all together and make a full name. Okay, again, pretty simple. Oh, yeah, Ken, sure. If someone knows how to do that, right on. Yeah. Yeah, once, not yet, not yet. Yeah, don't worry about it. There is. But not yet. Okay, so again, what we've got here is we've got just a basic. Oh, big win. Maybe we can do the same issue. The knowledgeable one make do happen. Not yet. Now I am in darkness. Total darkness. Okay, is that all right? Okay, cool. Yes. Not good. Well, okay, so we'll come back, we'll come back. Okay. So, so again, so we're just talking that we've got just a basic model here. We've got a full name method that's just going to concatenate the first middle and last names together. And then we've got this kind of permissions, a collection that's happening down online 23, that just simply is going to collect an array of permissions, whatever those are going to mean, eventually, right? Again, let's not, you know, we don't need to worry too much about this code here, just just give a sense of context, right? Simple 26 lines. Here is an example spec that is really common. Okay, really, really common, right? So what we have here is, you know, just looking at the top of the file, we're going to include the spec helper. Our spec helper, if you're not familiar with that in a Rails application, or just any kind of any test suite is going to do a lot of our setup for us of the suite itself, you know, include any pertinent libraries and, you know, things of that nature. And then, you know, just kind of reading through from the top, you know, we're going to describe user accounts, right? We're going to start there. And then, you know, now we're going to get into where we want to start to do a little bit more description of our validations, right? So, you know, we're going to say, yeah, so we're going to describe user accounts. And, you know, then we're going to describe the length of the first name, right? This all seems to make sense, right? I mean, we're describing these two things. Yeah, there's no issues here, right? And then we're going to put in our first set of assertions and we're going to say that it should not be super long, right? I mean, this all makes sense, right? There's no issues with any of this, right? No problems anywhere, right? And so inside of line six, between line six and nine, you know, we've got, we're going to set up a simple user model, right? Who doesn't do that, right? We're going to do this. And we're going to say, yeah, we want a new user. And then our first name is going to be really, really, really, really super, super, super long first name that is crazy long, right? So, you know, so this is going to effectively, what we're trying to do is we're trying to test basically line five, right? So we want to know that, that the validation of first name, that it's present, and that it's a length between two and 50, right? And, and again, in our example here, now, I know there's matchers for this, but bear with me, is that we're going to, we're going to test this basic assertion, right? On line eight there, now this is the actual test itself, and we're going to use, yeah, we don't believe in the expect syntax yet. That doesn't mean anything to us. That is a dead language. Just kidding. So we're just, you know, we're going to say if, you know, user valid, and it's going to return true or false, and then we're going to say, but it should not equal true, right? Okay. So we're going to jump over here for a second and we're going to say, yes, we're going to say bundle, like spec, spec, spec, models, user, spec, we're going to run it like the speed of light. Okay. And actually, just for this example, we'll just run line six, like the speed of light. Okay. So we've got one example, and no failures, right? Or at least when we run line six, right? So on the surface, this seems to work well. Does anyone see a problem with this yet? What? Just that's right. Anyone see the inherent challenge of this? So what are we testing for a second here? We're testing that valid is what? Anybody know? Somebody with a five, tell me, what are we testing? Valid is what? Not perfect. We are testing that user valid is not true, right? Okay. So again, let's, let's take a look back at our code, right? Okay. So we're, here we are with our code. Okay. So we're looking at line five, right? What is one, what is one component of this validation? We are testing for what? Very good. Okay. So that it exists, right? The test, the second component is that we're testing that the minimum length is what? The maximum length is right? So we have those two validations, right? Okay. So that's all fine and dandy. Now let's, let's give it a war. Whoops. Okay. So going back to this spec right here. Let's look at this again and go, okay. So we're testing that valid should not be true, right? Okay. So let's find something out real quick. So our assertion is between that it should be between two and 50 characters, right? Okay. So we'll just comment this out for a second. All right. And we're going to say user, we're going to write it again user, we're going to test the first name is between two and 50 characters, right? Right? So this is going to pass, right? So our test is now going to effectively be broken. Is that correct? Okay. So let's run it again and find out what happens. Do it with me. Come on. Now can anybody raise their hand and tell me why? Why is it continuing to pass? The other validations are getting it to fail, right? So the problem is, is that we've got a couple of issues with this test from very, from basically the beginning, right? The issue that we have is that we're trying to, in this point right here, we're trying to test a single field, a single attribute, right? But the problem is, is that we have other validations, right? So when we're trying to test valid is not true, the issue that we're running into pretty much right away is that we're trying, where our test is failing, we're getting a false positive, right? This is a problem, right? So what this, okay, so now you can go to the repository, now that I'm going to lose your attention here for a moment. So if you want to go to it there, we created a little thing on codingzeal.com slash skinny. And by all means, please fork that puppy, star, whatever you like. It's just a basic Rails app. There's nothing special to it whatsoever. There's going to be a couple of examples, like a single model and a few specs. Again, no big deal, no real configuration, you can run bundle, all that sort of stuff. Raise your hand once the internets have crashed. Internets have crashed! Okay, I can't, I can't fix them. I'm just raise your hand that they've crashed. Okay, so basically the, again, the format of this is that I'm going to go through a handful of these examples. I'm going to illustrate the kind of core principle and then I'm going to let you guys go at it. If you've got your own code that you're working with, I can even recommend a couple of open source projects that are awesome to refactor. I highly recommend that you do that, because it's kind of a great way to kind of experiment with that. One of the projects that needs a little bit of help, and I say that in a really positive light, is CanCan. Obviously that I think there's like CanCan community. There's a lot of tests in here that could really benefit pretty heavily from some of this, some of this work. So if you want to experiment with that one, or this project, by all means please do. But yeah, we'll go from there. So Skinny is just a CMS that is Skinny that has nothing in it, basically. Okay, that's a good point. I don't know, maybe. Anybody have a USB stick poking around that they could put it on there? This is a room of people who would destroy my show. Just kidding. Okay, so one of the core principles that we're going to talk to here for a second is, what is it? So we're going to start with this idea. Okay, and this is function from the pattern of a minimum valid object, an MVO. Okay, and here is the principle to that. A minimum valid object is going to be from the top of my spec permutating through the remainder of it. So cascading down the list, I will always know that at the very top layer of my spec, the object that the subject that I'm working with is valid. Right? So then as I work through my spec, as I begin to add more assertions to it, as I add more tests, all I have to do is mutate the validity of the object and test against that. One piece at a time. Okay? Does that make sense? Right? Okay, so this is a core component to a solid test suite. There's a lot of benefits to starting this way. Now, there is a gem that is really fantastic that is based on these principles. How many of you have heard a factory girl? Okay, factory girls are really, really useful tool, but the where it goes wrong, where people tend to use it poorly, is that they forget that a factory should only represent, in its base form, it should only represent the minimum requirements of a valid object. That's it. Okay, once you start to add in things to that object that make it that are optional, then what happens is you're playing with the validity of the object in a way that you can't you can't have control over when you're running in your test. You don't have confidence any longer. Okay? So looking back at the code, right? So the first thing that we're going to want to do is we're going to want to build up our minimum valid object. Okay? So let's just start with a subject who is not familiar with what a subject is. Okay? So basically the subject is the entity that your tests will be working against. Right? The subject of the test. Right? You can create, you can change this whenever you like, but the pattern is that you're going to start with the subject. Right? Now, so starting from the top here, so there's a couple of changes that we're going to make and our spec is pretty cool in a couple of ways because it will actually imply a subject for you if you don't declare it, if you do something like that. Okay? So our spec is pretty darn intelligent, as are many of the testing frameworks, that in the describe block here, if I specify an actual object, see how it's not quoted, right? But the actual class itself, what our spec is going to automatically do is it's going to set up this. It's going to effectively run this from the beginning. It's the equivalent. Right? It's going to create just a new instance and it's going to pass nothing into it. Right? That is something that's all fine and dandy. My personal preference is that I, I like to explicitly set what the subject is because again, we're talking about developer happiness to a large extent. And as on a dev team, you know, we might have six, seven, eight people working on a project at any given point and they all have to have a sense for what's going on. Right? Now, if we follow this common pattern here, right, and just, and which we do to a large extent and just say that the top describe is always going to have a class passed into it, then it's actually, that's a convention that's pretty ubiquitous with the testing methodologies. While at the same time is, if your minimum valid object is in fact not this, right, then you already have run into issues. Right? Because what did I say before? You want to start with what? Minimum valid object, right? So if that isn't valid, in my opinion, that's a no go, right? You want to start from a minimum valid object, right? So what I do is, even though I put the describe in here, I am still going to create my minimum valid object. So looking back at our code here, we're going to start with the first validation, which is that it has to have a what? First name, right? All right, we're going to say it's Jimmy. Okay. And it says that's between two and 50 characters, which were good. Does it have to have a minimum? Does it have to have a middle name? No. How about a last name? Okay. So we're going to say a last name is Jimmy Johnny. Okay. All right. Does it have to have an email address? Hmm? Okay. How about a password? Okay. So we're going to say password. Oh, dang it. I just used my password. Wait. There. Okay. I hate when I do that. I hope this isn't on the inner webs. Okay. Oh, sorry. I jumped ahead. What also does it need with the password? Confirmation. Yes, it does. Okay. All right. So we're going to say that again. Okay. So password one. Let's do some word wrapping. Yeah. A little gooder. Much gooder. Okay. So our subject from the get go is going to be a minimum valid object. Right? Now, for those of you who are not totally familiar with subject, from this point forward, you can refer to it as subject. So just as an example down here, let me say I'm going to, it should have a first name. Right? So again, I'm going to use should right now, but we'll get into expect. I do know that it exists. Okay. So we're going to say subject first name. All right. Yeah. First name. Right? I can actually, I can pull against the, against the subject itself by just calling subject. However, what you can also do is this is a method just like anything else. Right? So you can actually pass in what this object would be. Right? So I can at this point, I can also say, look, I'm going to do it just for all of you. First name. Two. B. Whatever. Right? Okay. So I can also call it explicitly through a name. Right? Basically a method that it's dynamically creating in the context of the spec itself. Okay? Basic stuff. Right? This is like, you know, we're getting into the, you know, we're like a level one. All right. Level one. Maybe verging on two. Okay. So again, we're going to start from a minimum valid object. Right? So now what we can do inside of our specs is we can start to use this subject entity and we can assert against it. Right? So again, we're going to start to refactor this a little bit because we want this to be a little bit cleaner. And I'm going to get into some other practices here in a moment. Right? So looking at line nine right here. Right? So we're going to eventually replace this object right here. Right? With our new subject. Right? This is what we're going to do. But we kind of have a little bit of a challenge and it's like, well, okay, but we're declaring first name up here. But I want to make sure that it's not super long. So how am I going to pass in this string and replace it with this item up here? Right? Okay. So here's what commonly happens is oftentimes you'll see something like this. And we're going to say user first name is now equal to this guy. Right. And now we're going to say user. Right. And then we can now assert against it. Right. And we're going to say, okay. So now user. Oh wait. Right. So now user. Right. Because we've we're calling it down here. Right. Does that make sense? Now we can say user should be true or should not be valid. Right. Does that make sense? Okay. But we don't want to do this. Okay. And I'll tell you why. So actually, well, let's just run our test real quick and see where we get. Um, we'll run line 12. Still, we're passing. Right. Okay. But here's the problem. Right. A couple of problems. Problem number one is that we're actually we still have the issue we had before. Right. So even though we've done a little bit of a refactoring here, the problem is that we haven't changed the false positive issue. Right. We still have this problem of, you know, we're still testing the validity in its inverse. Right. We're saying that valid which should be true should not, which means it is not not be true. Right. One zero one. Right. I mean, we've got this really kind of wonky assertion in here. So again, we visually know that this is a problem. We've kind of addressed this by refactoring some of this code, but we actually haven't eliminated this testing problem. Right. So here's the next principle. And well, I'm going to jump around a little bit. And that is thing in here. Oh, actually, we'll start with this guy. Right. So just as an example, let's look at this simple expectation. Right. It and then we say object valid should not be true. Right. Okay. Now here's the problem with this is that we're saying that valid which we're expecting to turn true should not which we're expecting it to invert that should be true. Does that make sense to anybody? Right. But I mean, it makes sense when you're writing you're like, yeah, unless it's not true, it should be not not false. Okay. So then if we put it in the expects in text, it's going to look something like this. Right. It expects object not to be valid. Right. Little bit makes a little bit more sense. Right. How about that? Is that a little better? Okay. Here's the principle. Test to true. Right. You want to test to true. That's what you should be doing. Don't test to false. Test to true. Because if you're functioning from the concept of a minimum valid product or minimum valid objects, excuse me, MVP, MBO, minimum valid object, then you know from the beginning that what you're always testing to is you're always testing to a true state. If it's valid, if it's invalid, the principle is I'm going to test to true, assert to true. That's what I'm trying to determine. Right. So again, from a developer happiness standpoint, it gets you to the, now again, we haven't actually solved our problem yet. We haven't done it yet. But what we are doing at this point is we're making it something that is readable and understandable so that we can easily see our issue. Right. We can easily see that, oh, I'm expecting the object to be invalid. Well, it's invalid for many reasons. What makes it valid? Right. So this is, so this is where the expects and tax, a lot of people complain about the expects and tax because it's like one of these things where they're like, you know, now I have to write all this stuff because I used to be able to, you know, make it look like, well, I used to be able to like make it look a little bit cooler and whatever. No good. Right. So always assert to true. A true state. Right. Now in our example, right, going back to our example, there we are. Okay. The simple way to test, the simple way to invert this, in a way that we're testing the true would be to just invert it. Right. So we're going to say user to be valid. Right. So if we go back to our test and we run it again, let me just make sure we're on the same line. Was there a comment? Well, so we're testing to be what? Oh, yeah, yeah, I'm sorry. I'm sorry. Right. I need at least two more hecklers in the room. Yeah. Invalid. Invalids. So we're testing to true. Right. Okay. So again, the issue here though is that we actually still haven't solved our problem. We're still working from invalid. Right. We're still, we still have the same issues that we had before. So now we're going to go through process of refactoring this out so that we can actually be true. We can be testing. We can run an assertion that would be what I wrote before, which is this. Right. We ultimately want to assert that our expectation is going to be that the user will always be valid. So we're going to manipulate the first name. Right. We're going to manipulate the first name and test that it's invalid. Right. But then we want to also go back to the beginning and test that it's valid. So one way that we could do it is we could actually include it up here. Right. And oftentimes when I'm writing, putting together tests, I will do this, but I generally will eliminate them as well. I'll write this temporarily just so that I can just so that I can make sure it's a little bit of a sanity check. And I don't think it's a bad practice at all. Right. So let's see if we're still, if this is still the case. Okay. We forgot our email address, didn't we? Say again. Let's find out. Of course I did. Ah, let's check our code here real quick. No, it's not optional. Yeah, I didn't do this. Right. So we are actually testing our test is accurate. Now again, this is not a very TDD approach. Right. Workshop be whatever. That there. Yeah. Yeah. Okay. So, okay. So we're getting a little closer. Right. We're getting just a little closer to where we should be here. Okay. So again, we're working from a minimum valid object. Now the next principle that we want to function from is so if we kind of continue to look through our code here for a moment, we've got this. We have similar kind of structure. Right. So we're trying to dry things up more and more and more. Right. And we want to get to the point where we can eliminate all. Oops. We can eliminate. Oh, sublime to Vim. How much I love you. So we where we can start to eliminate some of this duplication. Right. The inherent duplication of this. Right. So here's the next principle that I want to illustrate. And that is this guy. It's controlling your values with let. Right. So the next principle is that you never there's a law. No, just kidding. Okay. This is the law of controlling your values. The law of Adam. Right. So the next pattern is and kind of core principle to this is control all of your values with let. Okay. All of them. Here's what this means. So in this example up here. Right. We're building this. We're building this user object right here with a bunch of attributes on it. Right. And we're passing in string values that represents all of these various states or these various values for these different attributes. Down here in this, this described block on line 10, the way that we're manipulating the value of first name on user is that we're having to call the user object. We're then having to access the first name. And then we're going to add a new value to it. And we're going to come down here and we're going to assert its validity. Right. Well, if you control all of your values using let's you can actually roll values over right. So as they cascade as your test cascade through its context and its describes, the let's are going to override one another. Right. And allowing you to create permutations on the same value. So I'll show you how this gets done. Right. So first thing we're going to do is we're going to create a let that represents first in caps lock first name. Okay. And we're going to put our value into here. Right. Johnny. This I'm going to publish this code. Yeah. Oh, I can't. Sure. Well, if you look at the repository, it's actually in the read me. Yeah. Yeah. Sure. I wrote it in German, but but this is really a training exercise only the smart survive. I'm just kidding. All right. And one more. Okay. As a side note, I've seen this done many times before where when you're dealing with again, I'm going to acknowledge there are matches for this that I think their shop thought about should have matches that are fantastic for testing validations. So setting that aside, there's a lot of gem support for this. And I guess that's the learning experience here. But in this example, we're going to do this a little bit more our own way. Okay. Say that again. The scope of the letters to the describe. Yeah. This describe. Yeah. Yeah. It's in the context of this described block or example block. Yeah. So one as a side note, I've seen this done before. Not a fan. Okay. Anybody know why? There you go. Exactly. Yeah. Simple principle. Right. So in terms of your let, right, I Oh, sorry. It's because it's because when, so again, how you access a let for those who don't know is it's treated just like a method, right? If if if I was to, oh, I'll get into this a little bit later, but so what's going to happen is when password confirmation gets called, right, it's going to then call on the let up here and return its value. Right. So what that implies is that if I change one, I'm going to end up changing both. Right. If I change the first one and I'm, it's going to automatically be changing the second one. Here's why it's not a good practice in the specifically in the context of password confirmation is you want the that you're, you should never have a have an example in your application where you have for password confirmation where you're duplicating another value for the confirmation. It should be two individual values that are added in. So in regards to this specifically password and password confirmation, never definitely never do it because I very possibly am going to also get a an inaccurate value there. Right. Okay. Okay. And then up here in my object, I'm just going to go through and replace these. Where is the so these are not, they're not automatically run and this is going to get into another principle. I'm going to show you here in a second. Yeah. You can, you can actually use, you can order these however you like. Personal preference, but it is preference is to put the subject to the very top. Right. Yeah. Yeah. Yeah. Yeah. And we'll get into instance variables over using let's here in a second because our spec has a lot of support for implying what the subject will be. So if you can do that, you can use let, but in terms of the conventions that are defined by our spec and a lot of the testing frameworks is that subject is the thing we're testing against. Let's and things like it are to control value state. Right. Clarity. Yep. Absolutely. Yeah. Yeah. And that's a big, this is the big reason why I am not if you can explicitly say this is my subject, even though we know that our spec is going to help us out and it's going to create the other version of this. Right. Again, our specs going to do this by default. I don't. I actually declare it myself. Right. Just to make sure that it's really, really clear exactly what we're testing. Okay. So basically, so what we've done here and yeah, it's a few more lines of code. I get that. Right. Is that we're controlling our values entirely through let. What this allows us to do is we can now replace this entire block with well, I'm going to before I replace it, replace it. So I don't have to write it again. So I can replace it with that. So what's going to happen is in the context, in the context of the example at the very top layer right here. Okay. It's going to use the first name value from line six. Right. In this let. But when it jumps into this describe to check the length of the first name, this let value here on line 15 is going to override the one above it. So when the subject gets built, it's going to use the let from the second example. Right. Again, we're like, we're like our spec to our spectish three right now. Okay. In terms of, does that make sense? Right. But again, we're always working from a valid state. So here's the thing. Again, if the convention is work from a minimum valid product, which means that what is this going to do? Just change first name and it's going to mean that it's just simply going to invert the object or invert the validity of the object. It's that simple. Right. So now what has happened in terms of we're talking developer happiness here and pattern is, I have an assertion that I know will be true. So again, we're always asserting against true. So if I run this expectation, it's going to return true. I know everything beyond this point. I can know that if it goes invalid, what has been affected is what I have changed. Does that make sense? Right. Core principle, always work from a minimum valid object. Right. And again, we can continue to go down this path. So down here in this example, right. So we're going to do a little bit of changing here. Raise your hand if you're familiar with what the difference or the usage difference of a describe block versus a context block is. Okay. Principle number next is this guy. Permutations using context. Okay. So again, one of the challenges that we have when we're writing specs is like, we've got all these variations. Right. I mean like going back to our code again. Right. Like going back to our code, we've got like we've got multiple things that could take this object out of valid. Right. And into an invalid state. We've got many permutations like what if the first name's too short and the last name's too long? Right. Do we need to test that now too? And the common and what most people do is they do. Right. They're going to come in here and they're going to say, okay, I need to, I'm going to run a test that is I'm just going to come down here and say it. It has a really first name and a really short last name. Right. Anyone ever seen this before? Yeah. And then what they do is they do something really smart and they do something like, okay, so I want to now, I'm going to now put two of them in here. Right. So user first name. First name. Right. Or actually, this is my favorite. Errors to include and then they like pass in first name too short or something along these lines. Right. Have you ever seen this before? Right. Let me ask you a question using this as an example. What are you actually testing right now? This is a Sandy Met sort of thing. What are you testing? Are you testing your code or are you testing Rails? Right. So, huh? Right. And that the errors matches means this. So if I go back and I decide to change my error message to be something like you're that stupid, why did you put that in? Right. Or something like that? Really? Yeah. Like really? WTF dog. I mean like, if I was to change it to that, now my test is going to break. Right. So this is no good. Right. So instead, again, what we're doing here is we're saying I'm going to control the permutation and where context come in is now I can wrap this in a new context. And again, context by definition is the context of the object at this point. So when first name is too long, right? Right. So now when I run this, let's run it and see what happens. So we'll do, let's do line 14. Shall we? Let's see if I have any syntax errors. Anybody? Okay. And actually we'll do, I don't know if you saw it, there's some really awesome formatters out there now. Okay. So if we read this, okay, it gives us a little bit more information. So all that I did if you didn't notice is I just threw in a different format so that it outputs a little differently. And normally I'll work from a dots, like just seeing the dots because it's easier to read. But again, looking at this from developer happiness, what we've got here is we're like, okay, user and user, and we're going to describe the length of the first name and it should not be super short, that it exists, shouldn't have weird characters. But we can also see this is what our spec is going to do for us is it's going to add in a new context, a new context that is when the first name is too long, it should not be super long. Right. Or actually, what would be better to make this a little bit more readable for the, for the world. Right. So now we can, we can take advantage of our specs beauty and we can say, okay, the user when the first, when the first name is too long, it should be invalid. Right. Pretty easy to read, pretty easy to understand. Yes. Sweet. No. Yeah, yeah, yeah. So contacts are, are similar to describes in the sense that they set up an example, a scenario in which certain things are true. Right. So in the contact and the, the convention when writing or filling in the description of a context, the convention that generally is used is that the context is going to start with when or with or as or something that's defining a behavior or state, specifically a state. Like again, like when the first name is too long, now I'm going to set it up. Right. I'm going to overwrite first name and I'm going to say, it expects user to be invalid. Right. Describes are treated very similarly. However, they are setting up more of a glow, the easier I think the easiest way to understand it is it just sets up a larger container of description. Right. So actually what I would do and again, it's just a naming thing is I actually will change the describe blocks to represent either the attribute and or the method that I'm testing. Right. So again, when so when I'm reading it because huh. Yeah. Right. So it's, it's easier for me to get a sense of what's going on to a large extent if your tests are written well. Right. Structured well. You can actually use them as documentation to a large extent. Right. If they feel and appear like documentation and one of the smells that we'll have is like you run the test weed in a nested format like this so you can see it all. And if it's just like, wow, this is a crazy novel I can't read then that's a smell that my test has got some issues in it. Right. Because it should be able to describe the things that are going on really pretty easily. Okay. Any other questions about that? No. Okay. So continuing down the refactor path here. Right. And using let's to do it. Right. So now what we're going to do is we're going to say a new context and we're going to say when the first here we're going to say when to short. We'll actually change this when too long. Right. We're going to add a new a left first name. Right. We're going to take our value here. Don't worry for all these okay. Right. So now we're going to test when it's too long. We're going to test when it's too short. Oh whoops. I actually need to make some changes. Okay. Pretty simple. Right. Now here's the great thing is we're setting up a pattern that is really extendable. Right. So again if we so and these layer on top of one other if we know that are at the top layer we're always dealing with a valid object. Then we don't have to hunt through the code to figure out what state of the object is that we're working with. Like we don't have to go okay. What's my okay my subject is this but I actually don't know what my subject really is. I don't know what state it's in. I don't know what condition it's in. I don't know what whether or not my test is actually going to be able to assert different values on one another. Like I have no idea but if I continue down this path I'm like okay. Well now I'm going to come over here and I'm going to say what's another validation we could throw on first name. Anybody? We could say oh oh we could just say we won't write the code we'll TDD this a little bit. Well we'll because TDD is actually the secret to existence as I developed. My whole world got screwed up. Okay when it includes the last name right and now I don't have to read everything above it. I can go oh okay so first name is going to be Jimmy and last name is going to be Jimmy. It expect user to be correct. Yeah. It uh no I know so I could now add an invalidation if I said for example like if I wanted to implement okay so here we'll just run it and you can kind of see what it's going to do. It's gonna so it's going to fail and the reason why it's going to fail is we just haven't implemented yet. We haven't implemented the functionality to test the two. So if basic oh oh yeah you're right it's not too sure. All right so we'll do that right. You're right could catch. But I'm not right not running the whole thing here uh 14. Just make it easier on everybody's life. What did I do wrong people? Anybody see it? Oh yeah okay okay oh yeah it should be invalid yeah yeah right right right yeah thank you. So in our second example this would be where we'd now go implement our code. But again if if I'm controlling all my values with let right I always I always know that I'm setting things up properly right and I also know that I can just continue to extend this. Right I can continue to move down the path and and change values on this right. Any questions to that? No actually but a general practice you could do that if you wanted to if you wanted to be a little bit if you wanted to confirm that a little bit more absolutely this would be probably an example where that would make sense to do that because this is one where you're testing that the two are identical. Yeah or at least in terms of your setup. Good question any other questions regarding this? Sir mixing and matching the context. Yeah so so if I was to continue down the refactor story I would refactor all of these. So I'm going to replace I would go through and I would replace these individually. Right so when the presence and now I've replaced this guy yeah. Does that make sense? Yeah so I'm mixing I'm just for the sake of that we haven't gone through entirely and entirely replace them. Yeah yeah absolutely and so that's part of the challenge actually is that because they're compatible it's easy to write it's easy to get into the process of writing a one way or over another because here's the other thing and this is this is one of the complaints that I've heard oftentimes is whoa you just added like five lines of code. I get that but in my production code where I'm really concerned about things like that for you know performance reasons right. When it comes to the specs I'm willing to make sacrifices like that so that it's easy to read. Right easier to read. Right you know there's a lot of talk obviously about the performance of spec. Right you know like how faster test suite's going to run is this going to be faster than that you know things along those lines and that's all valid if that's your primary concern. Here's the thing that I've experienced that we've experienced a lot of which is the function of a test is to assert what is and is not correct. Right that is the function of the test. Right so if that is not so if as a developer and as an engineer I do not have the healthy enough degree of that I'm not as confident about that being the case then my test suite actually becomes less and less relevant to me. Right I'm going to end up doing a little bit more click through testing. Right. But this is a way that I can do that and and control this. Right. So um yes specify what is yeah so did everybody catch that question comment. Okay basically what he's pointing out is he's like okay so looking at the code looking at the context right here. Right. What we're saying is when it's too short what does too short mean. Right. He's saying like should I be more descriptive about whether or not what too too short implies. Right. Should I say it's between two and 50. It's less than two actually or it's too long. It's over 50. And the answer that is actually a little dynamic. Right. So here is it's a good default to to put it in there. Here's where it actually becomes a pain in the rear is if you go if I all of a sudden want to go over here and say two characters or three characters or less is too short. Right. The only change I have to make is there. Right. And everything now too short becomes implied by my code. Right. It's easier to update that. However my test still isn't telling me that. Right. It's not telling me that it's the the number three is the one that matters. Yeah. And so in that regard clarity is king. Here here here's what I would say would be the rule of thumb and that is that if you get into a situation where you're doing something like this you're like this is going to be an exaggerated example. So when when the name has a that in it and is less than three and has a dog icon on it. Right. What's happening at this point is you're like OK now I I don't have to just change my test. I actually now have to go through and figure out what the heck is what. Right. And that becomes a little bit from a maintenance standpoint a little bit of a challenge. But at the end of the day is I want my tests to be very clear as to what the heck is going on. So to your point. Yes. I probably would put in that it is under two or it is over 50. Yeah. Good question. Any other questions out there in the visual the world. Now I use the style to understand what I've done. Yes. And go down there. Is there a way of getting on that. I mean I remind you of that sort of. Yes. And he's talking. He's talking about the shit but he has. Yeah. He's going to go all the way up to figure out what is this what's my state. Yes there is. You're in luck today. Thank you. I'll get I'll give you twenty dollars later. OK. So let's go back to our different examples. Right. I'm going to get to that here in a second actually. There's a couple of other points that I want to make. Right. One of them is this. And that is be descriptive. How many of you have seen something like that. Raise your hand if you've ever put a number in to represent which object we're talking about here. Do it. Raise your hand. We're all friends here. OK. So then what happens is you have something like that. Right. The first one's passing. The second one's not passing and you're looking at this and you're like oh yeah. Of course. Because user two is invalid dog. You're like cool. And my comment to that is what about it is invalid. Right. Now let me ask you a question. What if we were to do something like this. Right. And now we got that. One person in the audience raise your hand if you have a sense of what is relating to the failure. Thank you sir. In the back. OK. So this goes back to the topic of descriptive naming. Right. In your production code you may for performance reason you may be like well I don't want a method that's named you know company entity with three users and forty two products. Right. In my production code. Don't forget that this code doesn't run in production. Right. And if it takes a couple extra minutes even if it takes a whopping five minutes to run your suite it can be worth it because it may take you thirty minutes to figure out what's going on. Make sense. Right. So descriptive naming is like really critically important. You should never be doing stuff like this. Never. This is a law. OK. So use descriptive naming. Right. So user with company user without company. Right. And then it becomes really easy to figure out what the heck's going on. OK. Another principle. Let's see what we got here. OK. So another principle of controlling values with let is the argument of instance variables over let's. Right. Raise your hand how many of you use instance variables in place of let's. Sometimes. You say sometimes do you have a reason why. OK. Sure. Yeah. A lot of editors. Right. Like let's look at this here for a second. Right. Like I'm using sublime for example. Right. And in this example. Right. How do I know that this is that and this. Right. But if I was to put in an instance. Well I guess in my editor I've turned it off. But right. For most editors or ideas they'll have like a different type of highlighting. So absolutely. Right. So here's an argument does. This is this is the argument for why. Go ahead. Yeah. So what I would say is there's actually a smell a smell in the code in terms of your assertions and in terms of your test because there's there's a few big values to a lot. OK. And here's a couple of examples. So let's say for example we're going to jump down. Let's describe for a moment our first our full name method. OK. So full name. Now again if we were TDDing this we would approach this a little differently. But for the sake of example we'll keep it like it is. Right. What our expectation is going to be that we have got three different attributes that we're going to concatenate together. We've got a first name a middle name and a last name. We're going to concatenate them together and we're going to put a space between the words. Right. Pretty straightforward and simple. Now you may be asking yourself. Well geez. Mr. Cuppey. Why do you why would you write it like this. Right. And not like. Just simply doing. You know this. Right. Well the reason is because in our code. We have optional values. Right. So what's going to happen is for middle name as an example. It could be nil. Right. So the concatenation so this this this array this method on the array compact is going to remove the nil values from the array. And it's just going to make an array of values. Then I'm going to join them together. So if I have a first name no middle name and a last name the full name is going to be first and last. If I have a middle name and a last name it's not going to first so on and so forth. Right. So we have anybody know how to do the math. How many permutations do we have with just these three values. That's right. That's actually a good point. That's actually a good point. Right. So we have but setting that aside like in terms of let's say the validations are gone. Right. We have a lot of different permutations. We have a lot of different possibilities here. Testing that becomes hell. That's right. That's right. So so testing this is going to be kind of is going to inherently be a little bit of a nightmare. Right. Potentially if we want to give it like really solid coverage now again arguably you know we don't need to do all this testing and all that stuff and I get that but setting that aside for a moment like if we wanted to be super rigid about it we've got a lot of variations in here that need to be tested and we've got a little bit of issue now here's going back to the topic of let's over instance variables. Okay. How many of you have seen something like this happen. So we're going to describe our full name. Okay. And we're going to say when all name when first name middle name and last name exist. Okay. So we're talking from a minimum valid object. So what's the only thing we have to add. There you go. Right. We already know this to be true. Okay. Minimum valid. So we know that to be the case. All right. So now what we're going to do is we're going to say it. It actually as an example I need to do it this way. This is what generally will happen. The man with three I am tri J and then of course I've got to bind these values into my user object. So I'm going to say user first name is first name. I did what I did what I'm sorry. What did I do line 24. So what's going to fail about this out. Oh just kidding. So I'm sorry. What did I do wrong. Has anyone ever spelled an instance variable wrong in their life. Right. How easy would it be to overlook this. Right. So let's say for example right. Okay. So we're like. Okay. So I need to make sure that this is running. So let's let's run our test here real quick. So we're going to do full name on line 14 14. Isn't that right 14. Okay. I'll clear it. Yeah. Wait. What a second. Wait. Hold on. I expected all three. I didn't get all three. Okay. I got a look at my code. Nope. This is all fine. Oh I know what I need to do. Binding.Pri. Okay. Okay. No. Okay. I don't need to do that. Yeah. This test is pointless. Okay. I'm good. Okay. So what did I do wrong. There we go. Okay. So just for. Yeah. Told me it failed. Right. I mean like all it's right. It's just saying oh I've got issues. Okay. Well I'm going to go hunt through the code. I've at this point in time I've got a callus right about here from beating against the wall. And I'm pretty positive that I should put in a letter of resignation here soon. Because I obviously can't figure this out. For this example all I'm going to do is replace these temporarily with this. Right. Just so that you can see the example. We'll run it again. We'll see what we get. A little bit more informative shall we. Okay. Anybody know why. Because let is generate a what. A method versus an instance variable when spelling correctly outputs what. Nail. There's a great few talks on the depth of nil and how much we want to fill that. But here's a perfect example right. Undefined variable or method last name. So where am I going to look. In one spot. Right. So this is an argument. This is part of the argument towards the value of let is that because it's creating a method itself. When you spell it wrong. It's going to say no method. Right. Or undefined method. Right. So this is part of that value. Right. But then the other thing is is speaking to instance variables is you can do similar things because in reality. All a let is actually doing. Is something. I mean it's a little bit more complicated than this. But effectively. We'll say value. It's doing this. That's essentially all that's happening. Right. Is it's creating a method. Through inheritance effectively. This is effective. This is essentially the same sort of convention. So this is why this this works. So control all of your values with let. Right. The other value and avoid using instance variables all together. Right. Might be a little bit more challenging to read. But this is this is why it can be hugely beneficial towards that whole developer happiness thing. Right. So just for the sake of example. And actually. That's not what I'm going to do. Which object we're talking. When I said all values. You have seen something like that. How many of you is be descriptive. This. And that is 14 still 14 still. What do I do. Good man. There we go. You can do that. However one of the downsides can be that if you're. And this would just be a pattern you can choose based on your actual implementation. But let's say for example up here in the model. It's going to return. So let's say you write in some code that says that if middle name for example is blank. I want a default. Now you have a failure again. Right. So in this example what I'm going to do is I want to say. I want to explicitly set middle name to be this value. I don't want there to be any question as to what's going to happen. And so I'm going to force that to be true. But both work. Right. I mean actually I would say that more often than I'll actually do what you're what you're saying and I would do something along this line. Middle name. I would say middle name. And I might even do this. Or and I would do this in this case. Okay. So that I. Yeah. So now I'm going to override the value but the default can be no. Yeah yeah yeah sorry so and then it cuts this guy out. Yeah exactly. Yes sir. Should you so so again the question is is should you calculate the value or should you so what's the expectation from a user's perspective. The calculate or the the actual strength. So here's the deal is if you have to test your test we got some challenge like if I'm like oh yeah I wouldn't write this like this this is Lamo. What I'm going to do is oh no actually what I'm going to do is I'm going to take my first name and then I'm going to take my middle name and then actually I'm going to take my last name here. And then what I'm going to do is oh yeah that's right I'm going to compact these and then I'm going to join them together. Okay and this should be the value that I get right. Right because I'm going to use this code to test that code. Which makes total sense. Yes. Why did you start out with a total in their application? Down here. Yeah right here yeah. Why did I use full name here? No yeah instead of the what what do you expect. Because I control all my values of what all a lot. Yes a lot of extra code. Sure absolutely you're going to add lines but here's the deal is now let's say for example I now add more assertions to this and this is going to continue down the path but this won't change. I don't have to go through and change any of those values. Right I'm saying here basically my lead is setting up my my core expectation. My core state of the object because I am saying that middle name will be this first name will be this. Our full name is going to expect to be this and now all my assertions are going to run against that. So whenever I need so in my code if I'm like oh I'm changing the way the full name is working. So now my expectations so let's say here we'll do here's an example. So now I'm going to say it I could put this in a context but for the sake of example I'll just put it inside the it here I'm going to say it truncates characters over right. So now what I can do oh this is one I would put in a context. Oh no no here we go. Okay it's going to be over 10. So let's see here one two three four five six seven yeah that was done. Is that 10? One two three five six seven eight nine ten okay okay. So by controlling it all by controlling everything through all of the values through let's all my expectations are run the same what I all I have to do is I have to work through a common convention that this is going to be where the value gets controlled. So if down in my messing of the examples right if down through here I begin to mutate full name to see what the expectations is going to be at that point then I'm still working through a common convention right. But if down here I start to actually pass values in which makes a lot of sense it makes a ton of sense then I it's very likely and this is actually what happens to me is I miss these expectations right. So I will use this pattern controlling everything through let to be able to allow that to be true. Well what if for some reason we decided to make the first name optional then our full name test would break right. Yes yes but that's so if you're taking a TDD approach you're going to alter your test first right. So I'm going to go through and I'm going to say well everywhere in which I'm using this now needs to be modified because the expectation has now changed right. Or if nothing else let's say that we run that scenario. So I'm going to go through and I'm going to test it and I'm going to go oh these tests break right. Now myself as a developer goes whoa that's actually the implications of a change like that. Do I actually want that to be true? Do I want that to be changing also? Okay any other questions? Does it answer your question? You have it maybe from another standpoint if you look at that test in isolation you see that middle name is it's been assigned but you have to know in order to understand this test that full name the first name and last name are required for the minimum value that object. So you would change it in the initial setup of the minimum value or viable right sort of valid that's a minimum valid. So you'd go up and you would maybe set first name to male if it's a valid first name is not valid. Yeah but the weird thing is now you have a context which says when first name, middle name and last name exist that's not actually stated specifically. So that's not actual. Yeah that's true. I've run through the same kind of thing where like yeah it is that's a context that now no longer exists unless you definitely keep your user exactly the same forever which is a part of the chaoticness that I guess you know. Yeah so absolutely and that's a that's a really good point and a good catch and that's part of it can be part of the challenge of actually structuring the tests or the specs in when you're passing in really descriptive blocks like this. Like oftentimes I will eliminate the description of the it and goes straight to the expectation because our spec will format that for me. Sometimes it's descriptive of enough many times or other times it's not. So it becomes something that's left to the individual to decide and which actually kind of goes back to your point a little earlier about should I include detail? Should I not? This is a prime example of where including the detail is actually working against me a little bit right. So yeah but good point good questions and good things to point out. Any other? Yeah. I have a question about something different that you might want to answer in a different presentation. So my understanding of the current RSpec convention is that copy bar tests now go in feature specs. And so it seems that there's some redundancy between the request specs and the controller specs and I'm wondering what Yeah so that's going to be outside of this. So oh sorry so his question is is now the convention when it comes to the use of copy bar and specifically with your request or your integration tests is that they're going to be encapsulated into into feature specs. So instead of described you're using feature and then instead of it you're using scenario right. And then he's also talking about with request specs which you might be using a request spec to test the API where you're actually hitting an endpoint and asserting the values that it's returning. And so when do you use one or the other and how do you dry that up? Is that kind of what you mean more between the controller and the request? Because those are both the controller. Yeah. So it's going to be a little outside of this but at the end of it I control the circle back around. Okay. So so the next just to kind of I'm going to move on from there the next thing that we're going to talk about is this guy and that is extracting common behaviors. So we're now getting to the point where again if we look at our code we're getting to the point where we're running the same expectation over and over again. Right. We see that. So our code's not dry anymore. Right. And if we change one now I got to change the others. Right. So then we're going to extract a common behavior. Right. Or a common behavior and a common expectation. How many of you have you worked with shared examples before? Okay. Cool. So I'm going to how many of you have absolutely no idea what I'm talking about. Just in general. Okay. How keep your hand up if that's an in general like I have no idea what you're talking about in general. Okay. Okay. Good. No. This is going to be fine. This is going to be fine. Here we go. So a shared example is very similar to a mix-in in Ruby. Okay. It functions in a very similar capacity. In other words, a shared example is you are going to encapsulate a set of expectations and as a behavior. Right. So let's say for example just to make a simple example here I am going to so we start with this code right here. Right. So there's a single expectation that's really common and it's that I expect the user to be invalid in this state. Right. Okay. So what we're going to do is I'm going to start by cleaning this up but now let's say for example that we are going to add additional expectations of things that are considered invalid. Right. So again, we talked about errors but let's say for example we want to test that everything's working and that there are errors present. Right. And so now if we want this if we want to be running this test or this expectation with all of the invalid now we've got to do this call and spotlight to fix my issues. Right. So we're going to have this go over and over and over again. Right. So we're in making our code cleaner we're actually making it less clean. Right. So what we can do is we can use shared examples to encapsulate these two expectations into one common behavior. We're going to say that effectively in this state the object is invalid. How we test for its validity is we say that we run the invalid method on it it will be invalid and we want to know that errors are present. Right. So a shared example is what facilitates that. Now there are a bunch of different ways that you can implement a shared example. Right. One of them is that shared examples can be scoped to the to the describe that it is encapsulated in or the context. Right. The example. Right. So I could come here and I could say well I have a shared example. Right. And in my shared example all I'm going to do is I'm going to take this bind it to the subject. That's not what I wanted to do. Okay. And so now I can actually replace what did I well found friend. Well found. Okay. And so now I can actually replace all of these with it should behave like. Yeah. So sorry. So I went back to it mostly because that this becomes an so this becomes an evaluated in the context of the explain. Right. So if I the reason why I go back and I will replace these with subject is simply because the subject in the context of this shared example may be changing. Right. Because I can use these elsewhere. I can actually start to say I want this subject to be some other entity. Right. So but I'll get to I'll answer this a little bit more detail here in a second. Okay. So a shared example is simply a way to encapsulate common expectations and bind it to some sort of explanation. Right. So as an example right here I'm going to say okay now I can take my two lines of code and I can bring it down to one and I can say it should behave like an invalid user. Right. Does that make sense. Right. To dry it up. Okay. So if I look at this question would you change the like the vastness of the you have to use it or there you're like I specifically think that my reuse is only changing the subject that I'm using in the vastness. You can use it as well. Where are you going? An invalid user. Here. Yeah. No. Yeah, yeah, yeah, exactly. And you're looking at where? I'm sorry. I'm just changing the location on use it to be subject because you're talking like use it but you're still basically starting with your example. Yeah, totally. Totally, totally. So here's what I will do here's actually what I do with my shared examples. I actually move them out to new files. Okay. So how many of you have used cucumber specifically? Cucumber and capybara to do like integration tests or anything like that. Okay. So in cucumber you're going to write basically a declarative process through which to test or assert something. Right. And then you have step definitions that define in an imperative fashion in more detail how this is going to be run or done. Right. Shared examples I treat in a very similar fashion. Right. So what I do is with my shared examples I'll create a new file that is the shared example. You want to specs support create a new folder called shared examples. We'll call these what should we call these? Is it? Say again. I can pull this out. Okay. So basically all that happens is I'm moving this into a shared I'm moving this into its own directory that is shared examples. Right. Which is which is more of an imperative format to running these collection of expectations. Okay. So now what happens is that in this context right in the context of using the shared example can actually replace this. Okay. Should behave like an invalid object. Right. So now what I can do is I can now use this this shared example for things that are that all they do is they have an invalid method on them or a valid method on them. Right. And it can be taken outside of just active record. Right. So what I'm doing is I'm making my code more usable. That's basically what's happening. Do both methods work? Yes. And it's really up to you to decide in terms of whether or not you're going to call it a subject or you're going to call it user or how you're going to interact with them. My personal preferences is I like the separation a lot. Like I like to pull them and take them apart. Okay. Yes, you can. Very good. Okay. Can you pass in arguments to it? Right. So here's another way to continue to dry this up a little bit. Okay. So we're actually going to come down here. We're going to use this guy. So yes. So this is actually in the spec helper. It's this line. Okay. So it's including everything in support. Right. Now again, you know, this is all automatic. So if you're when you're installing our spec from the very first time and you run the generator for our spec install, it's including the spec helper and this line is in there. Right. So the assumption is the convention is that anything like this is going to be under the spec or the support directory. So spec and support and it will load all those load all of those files. Okay. So yes, to answer your question, it is included by default. Okay. So these behaviors here can take values into them. So let's yeah, absolutely. So his comment is that this feels a little overkill because this is a very simplistic example. And that's very much the case. Let's see. Let me show an example. Let me show you what I was looking at. So if you can see here is an example. This is from can can. Okay. Where there's more complexity that's baked into here and our expectations are fairly common. Right. Like as an example, where we're asserting against that's okay. Now we're going to open Xcode. That's no good. Quiet time Xcode. Yes, ignore you. Okay. So here's an example from can can. Okay. And this is a really common situation. Okay. Is that again, we see a lot of stuff. Again, this code runs. Right. It all runs. The expectations do go green. But what we can see is we can see things like we got instance variable usage. We've got a lot of common expectations that are being duplicated over and over again. This would be a perfect use case. A prime candidate for the use of a shared example. Right. Because in this situation we could clean up this code a lot. And tell me other than through the description, is it very readable? Is it easy to understand what's going on without your program or brain on? Not really. Right. It's a little challenging. Right. So in terms of developer happiness, we're kind of throwing it out the window just to touch. Right. But I mean, don't, I'm not criticizing can can. It's a solid, awesome product. Okay. But what we can do with these shared examples is we can start to encapsulate even more of our functionality. Right. So let's look at, where is a good example? Gives you back a shared example. In the back trace of the spec failure, it'll give you both, actually. It'll tell you. Yeah, it'll give you both. Yeah. So, let's do the concern. It's actually the concern of both. Right. It's dry and readable. Well, in this example, it's two lines with one line. Yeah. Yeah, yeah. Yeah. Oh, yeah. So in the, yeah, exactly. Exactly. Exactly. Let me see. Okay. So here's an example. A good thing I kind of loosely put this together. So I'm going to show just kind of a brief example where we can encapsulate a ton of functionality and leave this really pretty darn clean. Okay. So here's a scenario that I put together myself. Right. That's it. Yeah. So the spec looks like this at the end. Okay. So this is all the permissions and it behaves like the user. All of the behavior is wrapped up in that one. So your shared examples can be incredibly powerful because what it allows us to do is it allows us to define in a declarative fashion what the behavior of the object should be. So now when I go through this, like again, we're talking about permutation. So or we were talking about permutation, like I can say what behaves so full name, it behaves like a full name with first name, middle name, last name. And I'm like, oh, well, actually now I also want to add in here. I want the version where it's going to behave like that with middle name and last name. And I'm done. Right. Does that make sense? Right. So behaviors, shared examples can be insanely powerful to really help support this. Now what this information here is the end here. I'll show you the let's first. Yeah. So here are these are shared examples I would break into individual files. So I'm going to say that I would not be putting this at the top of the file, but for the sake of explanation, that's where they are. So this is a shared example for user. Okay. And you don't have to put it pass in a string. You can also pass in an object or some sort of entity. Right. And I'm doing all of this setup in one spot. Right. All of it in one location. Right. But these down here, this information gets passed along to the example itself. And it comes through as variables in the block with options. Does that make sense? So it's just like normal code. Right. This is all Ruby at the end of the day. That's all this is is Ruby. Right. But what this is allowing me to do is it's allowing me to set up what the common implementation is from an expectation level. Right. Like the user by and large is going to have these attributes. It's going to have these core expectations, these permutations, so on and so forth. What the only thing I'm going to be manipulating is values ultimately. Right. I'm going to say that in the scenario where first name and last name exists, all of this stays true. Right. But it still should behave like a valid user. Right. Or it should still behave like user. Right. And I can do the same thing with my full name too. So again, I would put this in a different example. Now the only thing that I would caution against is, and I kind of stopped in my example, but is that there is a decent amount of logic that's happening right here. I would caution away from this. I mean, if I continuing down this path, if I was to continue to implement this, I would work to eliminate as much of this logic as possible. But ultimately, you get the idea that this is a way for us to use Ruby as a language to program our specs in very simplistic terms so that we can come up with ultimately something that's very, very easy to work with. Very, very easy to work with. Does that make sense? Right. Any questions about that component today? Yes, sir. So you're passing in an array, but it seems like you're handling like a hand or side. Oh, yeah, that's all. I'm sorry, that's my mistake here. So you can, I think my example was incomplete. My apologies. Yeah, so, yeah. So you caught that. I'm calling this because of the question, so I apologize if it's confusing. But the fundamental component to it is this, that with a shared example, what it's going to allow you to do is the first, this component, it behaves like, so it should behave like, and then there's, it behaves like, there you go, the alias to the same spot, is going to be your declaration of behavior. Beyond that point, you can pass it metadata and actual values. You can do both, right? And those values now present themselves instead of behavior, right? So you can use those values to do whatever you need to do. Let me see. Sorry to find. Another thing that you could do with this is you could actually pass them in as let's. So in the example here, so I'll say it behaves like a full name with, I can say let first name be, okay? And what this will do is it will utilize these let's in the context of the shared example, right? So here would be another argument for why an instance variable would be a pain in the rear because you can't actually pass it in very easily, right? So these examples up top are the use of the metadata that you can pass in. Other things that you can do is that you could pass in admin true, for example. So you could say I'm going to set up this entire very large scenario where it's testing the full name, it's testing permissions, it's testing the user validity, it's testing all these things. The only thing that is changing is that now it's an admin, right? So I can say it behaves like full name with or it behaves like user where the name is Bob and then below it I'm going to say it behaves like user where admin is true. And just like that it's done, right? All of my behavior is encapsulated inside of this effective mix-in is essentially what's happening and I can now use that to manipulate this. Now again as a developer, I mean tell me, be honest, like if you were to come to this and you were to look at it this way, is this a little bit more understandable as to what's going on how and why? Right? I mean there's more to it, don't get me wrong and your tests are going to and as you're structuring your tests there's more and more to this that's going to happen but the bottom line is is that this is a way, this is the pattern that you can use to really dry up and make this more behavior and declarative than imperative inside of your specs themselves, okay? So we are, in terms of time-wise, we are about quarter to 12 so here's what I want to do is I can answer any questions but then because it's kind of in the workshop fashion is in terms of shared examples there's a lot of great, everything that I went over here in terms of documentation on how to use our spec is ample, it's all over the internet but what I'd like to do is like open it up in terms of being able to walk through examples and be able to code some of, wire some of this stuff up because shared examples as an example can be, I can walk through exactly how this works if that would help but I want to just leave it to in terms of the experience of the room what you guys want to do, yeah. I do have a question on the shared examples. Sure. I'm going back to an earlier comment you had on tests of your tests do you have any guidelines or laws on when it's too much in the shared example or is that your past values? Yeah, so like I was saying like this is a, this block, this kind of chump right here from lines 28 through 43 ow. This would be, this would be a scenario where I would be very cautious, right? Like I would go okay how much faith do I have as a developer that this is going to function as I expect, right? That's the boundary, right? Because what I don't want to do is I never want to get to a phone where I'm actually testing tests which I've actually watched done truly, right? Like I've seen it done and I'm like well no I mean because it's all Ruby and I want my Ruby code to be super sweet and it's like ew it's great and so you know I'm going to have, I've seen this too, this is the craziest one. I've seen people create classes that respond to call the method call and so they can pass it in in the form of a block as the example, right? Here's what I mean. It's a wild thing. So basically replacing this with what would be the equivalent of and then they're removing all of this. Right? Does that make sense? See what's going on. It's just, it's instead of actually using the behavior of the block in this context I'm actually going to encapsulate it in its own code. So that all sounds fine in Dandy. Like if you want to make your code super dry you're like well yeah of course you're going to do that, right? Because I'm a Ruby ninja. But the reality is, is now I have this entity here that's not actually tested in the longer term, right? And so how do I know the block's working like it should work? How do I know that that I'm passing in like in the context of our spec properly so that it works, right? So there's, it's really easy to go way too far down the rabbit hole with this stuff. So what I would say is there is a boundary. Ultimately, my preference is to get the code to a point where I can identify clearly what permutations are being tested and what ultimately is the variable in there, the variable entity, right? Admin, first name, middle name, last name. And actually T, here's a question about this. So this is actually first name. So this is an example of using it to come through the names parameter. Okay. So in my, in my example I may have a situation where I am going to, you know there's all this setup right? I mean there's all of this that's happening ultimately to run that. Right? So this is a way for me to kind of help support that cost. Right? Does that make sense? Yes? Questions? Is there an analog to shared examples for for setting up state where in a more flexible way than a forward one? Like as a So ask that again if you have a scenario. So let's say there's a particular you should have a pattern or other places that you want to use that particular sequence. But because it's a cross-chose or something. Yeah. So another common practice would be to actually create helper methods. Yeah. So the next layer to this that you could use is you know again we have so his question is fundamentally that what if you have like a common runtime order? Right? Like you have you have some setup but it's not really set up in terms of a before, right? Like but what you're doing is you're like in his example he's bringing up like a capybara and a feature test where you're you know stepping through links on a page or you're you know I'm visiting this URL and I'm visiting this and I'm visiting this and I'm posting this and visiting this and visiting this and that's happening every single time. Granted your features are going to run crazy slow but you know but say that's what you're trying to do is you're trying to make that a common sequence. You can use helper methods to do it and a helper method is like any other method you're going to define you can define it a multitude of different ways but let's do this. So we'll just include our spec helper for a second just for this example we'll use a describe here and we'll say we can use a feature that's fine feature and my scenario is when the okay so in this example we're going to have you know we're going to visit the login URL and we're going to fill in let's say email with dang it I did it again you guys are getting bored of my humor I can tell okay I think it's click on isn't that right submit I always forget okay so and then we're going to say that page isn't it it's a current page is that right so so in this example like so we might have this code right here that we want to run over and over and over again right again it's going to be slow but setting that aside let's say we're going to run this over and over and over again yeah rock that I was like okay so you can create helper methods to support this and a helper method all it is is a method right so you're going to say login with valid right and then we're okay it's it's visible in that scope in anything that cascades down yeah any so right so there's two ways to do this one is you could actually declare a method now but here's a here's the downside is if you get into the habit of doing this a lot now you've got all of these methods that are being defined right and they're just like here's another one you know and here's another one and here's another one so our spec has got a really great simple tool for that and that is that you can actually mix in helpers okay as micros or macros right so you can actually mix in just like you would a module mix in for ruby you can do the same with class and instance variable type stuff so these would be considered these are going to be put on within the context of this example object which is the rspec example object right but let's say for example that what I want to do is I want I want to create an even more complex scenario where I want to pass in specific values like for example right so now what I want to do is I'm now going to do where username is this and password is that right and I'm going to replace password right and now I'm going to use it down here you know I probably breaking rules here we go right and I'm going to use those credentials like a password around like a method okay but what our spec has which is really awesome is that you can actually define helpers right so you could say that ruby I'll do a module that is authentication helper right and I can do just like I would if I have just like I would in a mix in for in Rails or anything that's using that has access to active support concern I can also say or not class pass methods right and I can define a so indicate authenticate with credentials I could have that then I can also just again this is all active support concerns just like a normal module so I could say move this code here okay right so again still mix in then in my spec helper I just include it right so I'm going to take this guy and I will put it in support okay yeah so again like if you've got so here's what I did and I moved there a little quickly so inside the spec directory I created a new subdirectory called helpers and again as a reminder oh whoops whoops this won't work I screwed this up one second this needs to be under the support directory yep there we go so inside of spec support I created a new directory that's helpers and then I just simply created like I would anything else I created an authentication module authentication helper module right just like you would helpers inside of you know like your application controller or controller helpers I just extended active support concern like I would that module and active support concern gives me access or convention wise watches for class methods being declared inside of another sub module and then instance very and then instance methods are those that are within the scope of the helper itself and then so that's one part of it so again a module like anything else I've just said that about 47 times but then in my spec helper and you'll notice that this is and here we'll pull some of this just fixtures so then at the bottom here I just include what module what helpers I want to you know config include helpers all of this is documented through our spec core so none of this is you know like the Adam Cuppey school of thought this one oh sorry I just removed all the common so this is a way to again encapsulate dry up everything so at the end of the day that the core belief that I have is that your specs should be your features your specs your tests you can also do this all through many tests as well like this isn't just an our spec convention but it can be used to really dry up a lot of things and encapsulating your your logic that ultimately is very imperative like it's a step by step procedural thing I work to encapsulate that inside of modules and helpers and then in a declarative fashion I will use I will call on behaviors and use shared examples to declare a behavior right it behaves like a full name with this right that's my declarative example now I can go back into my shared example whenever I want these expectations to be changing I can go back to it and say well what defines a full name now what defines that behavior is step a b c or d right and all of these and they'll now still hold is true right in terms of they stay in the code that way does that make sense I didn't and the only reason why I didn't is because I didn't have any of the routes or anything like that set up the authenticate anywhere the mix in this guy right here or which one of you I have a comment like a book question please one is why did you need to get into the active support concerns I've used helpers for logging in and actually that's my comment which is that's not the whole story because we're in a test environment there will be no user to validate against so we often end up using stubs to right be able to actually log in and take out the authentication because we're not testing authentication we're testing the correct that's right yeah and I am sure I don't remember needing to get into a whole active concerns there so what did that so active support concern as a library is just helping the module mix in process that's it so I could replace this what it's for active support concern applies more convention to handling modules and specifically or not modules but mix ins and modules into other ruby objects right the masses so the that's why I'm wondering how you use this because we just use it as a helper and our spec finds it no problem does what I wanted to do was I was gonna help her if you use right right right right yeah yeah yeah sorry so so yes so if all I was doing was this I wouldn't have to use it I wouldn't have to I'm sorry to kind of make that a little bit more confusing that's right so because I'm creating a class method entity here I'm using active support concern to utilize the convention of a module sub module called class methods which it's going to help with that right so in the example maybe to clean it up and make it a little bit more clear it would look like this right that yeah sorry so I'm just it was more to kind of answer and address his question so like that would be its use right that does that answer your question a little bit a little bit okay a good point yeah absolutely so our spec three if you could hear could everybody hear what he's saying okay so our spec three they're changing some of the kind of the the ways in which you can use for matters and in the examples I was using I was you know running the test and I was passing in tack tack format space nested right and that was to use the nested format so that we could see that in our spec three they're effectively going to be deprecating a lot of that and what what you're going to be using instead is what's it called it's doc documentation yeah okay it's just a documentation I thought I had a different it's like I'm sure which nested is a anyway yeah yeah so documentation format so just as an example that's going to come along what I would say is everything again everything that I've talked about here the our spec documentation through relish app.com is actually pretty strong however there's some weird linking issues like you know you could be looking for one version of the documentation and it's hard to find the other but it's actually really good and I'll bring it up here real quick so you can see it let's see our spec internets are you alive today talk to me interwebs next door this one ooh that's nice yeah I feel like Steve Jobs having you guys to telling you guys to turn off Wi-Fi so my iPhone will work should we expect something to behave like no so the the expects and tax hasn't changed at all it's still the same it's just it's I it should behave like such and such because it's encapsulating other expectations it's within the block actual assertion in the in the example itself so in the example itself it's exactly the same you don't you don't use we'll know because this is not so this is not an expectation or an assertion itself this is an encapsulation of behavior so all this is doing is this is this is just a convention of calling the collection that is the shared example yeah yeah so I've got a long series of long for a different set of users put in the shared example with you break the shared example down these shared examples does that work you can't you definitely can oh sorry the question is is can you effectively nest shared examples right so I'm going to put a shared example on another shared example and the answer is that you can to a certain you can to a certain extent but I don't really recommend it and it's and the only reason is because the the function of a shared example is to encapsulate the imperative style of your expectations in other words like it's to encapsulate sorry let me say this simpler it's to encapsulate your expectations right these are the five things that need to be true false whatever right okay and so it needs to be used in that context when you start to nest like continue to nest not only does it become harder to track like when I look at this behavior for example when I read it my sense is that it's testing full name that's what it's testing but if it's also I've actually thrown in shared examples that are now going to test first name too right so I've got the shared example for it should behave like a first name with this and it should behave like a middle name it should be on the last name when I read this spec it's hard to know all of that's happening things are going to start to fail potentially but from a developer happiness standpoint there's that so I would actually break them up and keep them as fair as shallow as is reasonable right does that answer your question so then how would you do it more um so I would split it up into shared examples but the conventions the convention that whoops that can actually so it would be a combination of shared examples and helpers right so what I would do is I could use I would I would break it up into shared examples and keep them as collections right I mean this shared examples folder might get larger well it's going to get larger right and I might have a dozen different files in there two dozen files in there that represent the different types of shared examples that I would be using um but that's perfectly okay because those aren't the things that are my tech those aren't the things that I'm looking through for my tests themselves right I've got a set of specs over here that I'm trying to read and understand the conventions that are being used okay but the separation of my shared examples are there then in my helpers I'm going to start to identify what things what common functions need to be utilized to either set up the scenario that I'm trying to run or or trying to you know or things that I may need to persist over time right so it's going to be a combination of the two right but really ultimately what it's structure ends up looking like is it looks like a Rails app right you've got models right you have controllers and then you have you know some view layer I mean like you've got these components you have helpers you know like you have these components that are all broken out but like looking at a controller which really is the spec right I mean like I'm looking at the spec and ultimately what it's doing is it's showing me a control type function right in a way in a roundabout sort of way right so this would be the equivalent of my controller and just like a good pattern when writing code in a controller is you keep them as fairly slim like you don't want to just throw a ton of logic in your controller actions for the same reasons right we want to illustrate the kind of core behaviors that are occurring what is the ins and outs and where does it need to go that help great so we're just about time so I just want to again like that we've talked a lot I want to just kind of summarize these components just so it's clear so one of the things the big things we talked about was controlling your values using let's you can do this again your let's they they cascade so they bubble up the chain and so because of that you can you know declare first name last name all of that stuff and then in a later context you can mutate that and it's going to bubble up the chain in a way that you know allows you to assert values instance variables if you spell them wrong then all you get back is nil versus if you spell a let incorrectly in terms of its usage you'll get a undefined method error so that is controlling your values with let descriptive naming again what we talked about is this is death right because again if we run our expectations when we have a failure when I'm trying to read it it doesn't really make any sense right I don't get a strong sense of what is going on however if I change the naming convention so it's fairly descriptive the end result of that is going to be that when I have failures I have a sense of what's going I have a sense of I have context right I have a sense of where the failure might be occurring in terms of differentiating itself from the other assertions that I'm also running okay this is probably the crux of it in my opinion is that if you want good solid tests that are really easy to add to extend dry up is that you start your test from a minimum valid object factory girl this is the core convention of factory girl most people don't know that as a gem and all factory girl does is it's a it builds objects that you can interact with so it's you know it's a mock of an object but again its core function is its core usage that is that should be used as is as a minimum valid object that you then mutate right we looked at this a little bit and this is kind of an argument for using should but again in terms of readability and the ultimate kind of takeaway this is that you should always be asserting to true right that's your goal is assert to true right and in this example it kind of makes sense it feels like that is the case right because I'm saying it should be true but that's actually not what we're testing what we're trying to test is that it's invalid right that's the truthy statement is that this is an invalid entity right the other thing we talked about is permutations using context so again this goes back to let's so ultimately what that means is that I can mutate the middle name for example and assert that things are still valid or invalid I can again I can assert to true and then as these contexts begin to cascade and I nest them more and more I can mutate the values inside these contexts with confidence that my expectation at this point in time in this layer is going to still work it's going to work as I expect it to work and this works in conjunction with a minimum valid object these two go hand in hand extracting common behaviors this is the use of shared examples something we didn't go into here because we kind of ran out of time but is really really powerful is to create custom matchers so as an example this is a matcher right here be invalid is a matcher method you can actually create your own so I could encapsulate all of the logic I'll show you just a very quick example so here's an example of death right has permission to edit the page and I have all of this crazy logic that's being run inside to test to extract the permission to test against the permission in fact the way this test is broken out is I'm actually going to set a variable called raise error then I'm going to iterate through the permissions I'm going to if the edit state and the page match then I want to raise an error and then and then it's going to and then it's going to raise the error and I'm going to catch the error and the expectation and assert that it's not going to happen that's basically this one of the dumber things that you can do so what I could do instead is I could write a matcher for it right so basically all I have to do is I say I expect user to have permission to edit page right so this is another way to encapsulate of behavior or at least the structure of the code to allow you to create that again all of this documentation is all on relish app and RSpec the RSpec core docs so you know it's not like it's not any unique pattern or anything like that okay and then declarative expectations this also talks to the shared examples so again the the declarative side of it is it behaves like it should behave like this right versus throwing all the expectations in there right so now what I can do is by having a declarative expectation it be a behavior I'm speaking to by doing that then I can simply add kind of metadata to that explanation that's going to change it right so in this behavior when admin is true I want you to handle it this way and tell me if the full name still is how it should be formatted right so declarative expectations like I said a little earlier if you guys don't know we our company zeal puts on a workshop it's an Agile TDD developers training and conference we're going to be doing it on October 22nd through the 25th currently on roguerails.com we are running basically a thing that if you add your email address it's going to go away on Sunday we're going to know you're from RailsConf and so we're going to throw out a pretty smoke and deal because we'd love to have you guys there it'd be way cool but ultimately what we go into like Ryan Bates and Kent Beck those guys were here last time they helped organize the event with us Ryan Bates who does Railscasts and can can so those guys help organize Kent Beck is one of the signatories of the Agile Manifesto so test driven development all that stuff he's very into so we put it on with them because we really want to train this stuff for the sake of developer happiness so that's what rogue rails is it's an event we run check out roguerails.com follow us on Twitter it'd be great again this is what I actually look like that's actually a headshot of mine but anyway I really appreciate you guys coming down I hope you feel like you got a lot out of this I will post the slides check out the repository I'll post notes there I am at Adam Cuppey on Twitter you can look up my name I'm probably one of the only people that have the name of Adam Cuppey but again I really appreciate it thank you for your time hope you guys had a good RailsConf and I probably will see you guys next year