Lesson 2 of 15

Continuous Tests

Duration: 21:35 Watch on YouTube (external link, opens in new tab)

Markdown version

Leanr how to set up a continuous testing solution using Guard and RSpec.

In this lesson

Roy Osherove installs the RSpec and Guard gems, lets RSpec create a spec helper and an options file, and lists the specs as a hierarchy with the documentation format. He writes a first spec for a calculator whose add method returns zero for numbers over a thousand, using describe, context and it so that the output reads almost like a sentence. He then creates a Guard file with only the RSpec configuration, has it watch the lib and spec directories, and runs Guard so that the specs run every time a file is saved.

Transcript

2,546 words

[00:02] (external link, opens in new tab) Okay. So, what I'm going to do is to create a new directory. I'm going to call it demos 3. Okay. And I'm going to move to that directory. And in this directory, we're just going to start from scratch. There's nothing there. Can you guys see the typing this better? Okay. So the first thing that I I want to do is to install the gem RSpec.

[00:35] (external link, opens in new tab) So I would say gem install RSpec. I should already have this. Now I don't have any internet connection here but I already have it installed so I'm not worried about it. But you should have it installed as well. Another gem that I want to have installed is guard. Gem install. Guard. Okay. I already have that installed so I don't have to install it here. But you have to have it installed if you want to have any kind of continuous integration working on your laptop.

[01:07] (external link, opens in new tab) So if we just start with with a project with RSpec the the first thing that's the easiest to do is to just say RSpec --init. And what RSpec in it does that it creates two important files for us. The one is the spec helper in the spec directory. So if I look at this, if I look at the tree, no, I don't have that installed.

[01:37] (external link, opens in new tab) Okay. If I look at the directory, I just have a spec directory and there's nothing in there that you can look at. But if I say vim for the current directory, you can see that I have the spec helper here. And the spec helper basically runs all the code that I would like to configure in RSpec and by default I don't need to touch anything here.

[02:08] (external link, opens in new tab) Okay. So you don't have to do anything to just start working. However when I run things with guard later it is also the thing that makes guard run in color. So you can have all the configurations for running things in color etc through this oh sorry that's in the RSpec file. So if I show all the files here sorry that's here. So the RSpec file over here that's the thing that by default gives some default options for RSpec if I run things locally.

[02:43] (external link, opens in new tab) So if I go to the local directory and I say or just RSpec now, it says no examples found. Okay, RSpec, no examples found, but I can see things in color, etc. And I can add more things. If I remove that and I go here, I say RSpec, you can see that now it's not in color. There are also other options for example the formatting

[03:18] (external link, opens in new tab) Formatting progress is what gives you the dots but it's better for me at least or for our demos if it just say that the formatting is is a document or for documentation. If I save that and I run RSpec, I don't have any examples yet, but I should see them in a form of a list, a hierarchical list like we saw before.

[03:49] (external link, opens in new tab) Okay, the first thing I want to do is to create we're not even doing test-driven development yet. I just want to show you what it's like to to write a test for something and then we'll move into a test-driven kind of mind. So, what I'm going to do is I'm going to say I'm going to create another folder here called lib. And that's where I'm going to host all my files. Oops, I made it here. So, I'm going to move it to out of the spec directory.

[04:21] (external link, opens in new tab) So, I have these two folders, lib and spec. And in lib, I'm going to write all my code. So, this is just a standards issue. In your code, you can decide on how you work. And I'm going to add a new file here. We can just call it my calc. And my calc doesn't have anything but a class called my calculator.

[04:52] (external link, opens in new tab) It could have a method called add def x and y and it would return x + y. Now I do want to have some kind of logic because I don't normally like to write tests for code that is purely mathematical. That's not what unit tests (external link, opens in new tab) are for. Unit tests are usually for code that has logic. you want to prove that the logic is working.

[05:22] (external link, opens in new tab) So I can actually say that it always returns for code but if the if there is a number that's bigger than a thousand that it ignores that number. I can say that if say return zero if x is bigger than th00and.

[05:53] (external link, opens in new tab) Okay. Now this is a piece of code that I now would like to test. I don't know if that actually works. But let's say that I found a bug and the bug is that I forgot to check why. I forgot to check why the argument. So if I wanted to write a test for this or a spec using RSpec, I can go to the spec directory and add a spec that is named after the class. I would say my calc spec.

[06:27] (external link, opens in new tab) This is important because this naming convention is how the runner detects things later in guard when we're running things automatically. So if I open it now I can just write a describe now by the way I haven't written anything yet but if I now go here and I say rspec what happens? Zero example zero failures. If I just say describe

[06:58] (external link, opens in new tab) Something do that's the simplest describe what happens if I go to the code and I run it finished zero example zero failures and here I just have a shortcut for controlB when I run it inside Vim which is the text editor I'm using but right now for you you can just do this RSpec on the current directory and it by default looks in the all the things in the spec folder

[07:36] (external link, opens in new tab) So if I say it does something what happens now let's see now this is starting to look interesting okay I I can see the pending and I can also see this list because I wanted to format it like a document ments then it looks very hierarchical. So something does something and it says pending not yet implemented because there is no nothing in the code that does anything. Okay. So let's make it do something. To make it do something I add the do

[08:09] (external link, opens in new tab) And end. If I just run it like this now it passes because there is an implementation. It's just empty. Without the do part there is no implementation. Here the implementation is do nothing. So it obviously passes. It doesn't assert anything. It doesn't check anything. So something does something. And now it's green. It passes. What if we wanted to describe our our calculator? I can say describe my calc.

[08:42] (external link, opens in new tab) Let's see what happens. Now it says oops uninitialized constant my calc at the top. So I need to require it. So require oops require and I would use the require relative here because this is a file relative to my file. I can just go like this. One folder back slashlib slash

[09:13] (external link, opens in new tab) My calc. questions so far. It's okay to have questions. This is why we're here. Okay, so I'm running. It says okay now the subject is my cal. Okay so describe my calc. So let's start by understanding what it is we're trying to test.

[09:48] (external link, opens in new tab) If we look at my calc, it has a method add and we want to test it with something that's over a thousand. So we can say describe my calc. We can say describe

[10:20] (external link, opens in new tab) So that this is the entry point (external link, opens in new tab) right this is the unit of work (external link, opens in new tab) adding numbers. Now we can say describe okay under what states over 1,000 okay so you can see the hierarchy now I can say it what should it do if it's over a thousand

[11:03] (external link, opens in new tab) Make sense so far? So I'm destroying my cal and I'm destroying the feature that's called adding numbers. And when things are over a thousand, it returns zero. So there's a special word in reserved in RSpec if you want to use things that are when you set up state for something and it's just an alias for describe and I can say you know what maybe it makes makes more sense in the context of over a thousand. Okay. So the word context and the word describe they mean the same thing in terms of the language underneath.

[11:34] (external link, opens in new tab) But in terms of our spoken language we can use it to describe the state to say describe adding numbers when the number is over a thousand it returns zero. See so it's almost like a sentence. If I just just run it empty you can look at it this way. My calc adding numbers over a thousand returns zero.

[12:11] (external link, opens in new tab) Sorry back C# in my head out new 101. That's very unimaginative. Any other ideas? Actually, 10001 is pretty good because it's the first number that crashes the boundary

[12:47] (external link, opens in new tab) Or illegal. So, what should be the second number? Does it matter? For the purpose of the test, it doesn't matter. So, but I do have to send something, right? What should I send? 666. If you looked at this test and you didn't write this test and you saw 101 666,

[13:19] (external link, opens in new tab) How would you feel? confused. Okay. So, what would make you feel less confused? >> One because it's the first legal number maybe. What about zero? Zero might be weird because you're going to see zero at the at the assert as well.

[13:50] (external link, opens in new tab) You can see zero two times. That might look a bit magical. So you want the parameters that don't matter to not matter. So so the person who reads your code doesn't have to ask unnecessary questions. So the the code of conduct is always assume that the person who's going to read your code is a serial killer that knows where you live. Okay? You don't want to piss them off. You don't want to ask them unnecessary questions. So if you make it zero or 666, they might just get the axe and come to your house and ask, "Hey, why is that 666 by the way?" And you don't want that anyway.

[14:29] (external link, opens in new tab) But one is pretty good. So that's the act. I need the result, right? And I want the assert. So how do you assert with RSpec? RSpec has very good APIs for asserting things. So I can just say result should equal zero.

[15:00] (external link, opens in new tab) Okay. I can also say let's see exact. Okay. I think I can say this as well. B 0 Yep. So if I go back and I add a bug and I say return one. Okay. Now I have to save it.

[15:30] (external link, opens in new tab) Go back and run the spec. Now you can see this failure. Result should be zero. Expected zero got one. Okay. So, it's pretty helpful. Let's undo. Run the tests specs. Okay, we're back to that. Now, some people like it, some people don't.

[16:01] (external link, opens in new tab) Personally, I like to separate with an empty line between the arrange act and assert. And as we have more test, we'll see that we might want to separate the creation of things, but we'll see how things go. Questions so far. Okay, before we move on, it's getting quite annoying to keep running RSpec and then I want RSpec to run even when I change the calculator. Okay, so what I want to do is to start setting up a continuous testing solution now using Guard.

[16:36] (external link, opens in new tab) So what I'm going to do to use guard you need a file called guard file which which is the configuration of guard. It's just like a gem file or anything like that. So let me just create a new shell window. And here on the left, I'm just going to say guard sorry, guard init RSpec.

[17:06] (external link, opens in new tab) Actually, if I just say guard init, what's going to happen? It created a new guard file. Okay. If I go to this location, I can see this guard file right here. And this is what it looks like. It initializes everything. Cucumber, RSpec, Rails, all this stuff. This is stuff that we want to watch out for and what to do when things

[17:36] (external link, opens in new tab) Change. So, what I'm going to do instead is I'm going to remove the file because it created too much gunk. And I'm going to say guard init rspec. So just RSpec please. And now if I go to guard file, you can see that it only has the RSpec configuration running.

[18:13] (external link, opens in new tab) And we don't actually need everything here. So let me just delete all the stuff that's not needed. I don't need all the Rails stuff. I don't need Capybara for now. I don't need turnip. I just need to watch the spec directory for something that changes. This is a regular expression. And I want to watch the the lib directory for if anything changes. RB. Now, if this changes, it automatically runs the spec file. If this changes, it automatically runs whatever is in here. So it looks for anything slashspec/lib

[18:47] (external link, opens in new tab) With underscorespec.rb. This is the naming convention we had. So we're we don't have a speclib folder. So we can actually just change that to spec. So that means that if anything in lib changes, I want you to run spec whatever changed spec rb

[19:19] (external link, opens in new tab) And if spec helper changes run all of spec. And I write that file and I exit. And now what I can do is just basically say guard. And now it's watching always watching. So if I go to my file and I just save the spec again, just write it to file, I should see it automatically running on the right side.

[19:54] (external link, opens in new tab) But it's still too much gunk going on in the screen. So what I like to do is to exit it and then run it with command C with the dash C. Dash C means that it always cleans the screen every time it runs. So it's easier to see. Okay. Okay. So now if I go to my to the left and save again I just see the screen.

[20:24] (external link, opens in new tab) Okay. Now even more importantly if I go to my calc and I change it and I save it automatically runs a spec for cal. So if I go and I change this to return three or return four and I save it automatically shows me that something failed on the right.

[20:59] (external link, opens in new tab) Now because I scrolled up I don't see it but it already ran again. So if I write it again here. So if you are scrolled all the way up, you don't see it. It doesn't scroll down again. I'm using iTerm here. But always make sure you scroll down. You should be able to see that screen again. Question so far. So it should be pretty easy to get guard running on your machine as well. And what I want you to do now is to try to get to this same situation on your machines as pairs.

[21:34] (external link, opens in new tab) Okay.