---
title: "Advanced RSpec and Cleaning Up The Specs"
url: "https://courses.osherove.com/courses/tdd-and-bdd-in-ruby/advanced-rspec-and-cleaning-up-the-specs.md"
canonical: "https://courses.osherove.com/courses/tdd-and-bdd-in-ruby/advanced-rspec-and-cleaning-up-the-specs/"
tags: []
author: "Roy Osherove"
description: "Lesson 8 of 15 in TDD and BDD in Ruby (Day 3 - Advanced RSpec and Faking), 25:44. Free video by Roy Osherove."
usage: "Licensed under CC BY 4.0 — reuse, quote and adapt with attribution (Roy Osherove, link to the original page)."
license: "https://creativecommons.org/licenses/by/4.0/"
---

# Advanced RSpec and Cleaning Up The Specs

1. [Courses](https://courses.osherove.com/#courses)
2. [TDD and BDD in Ruby](https://courses.osherove.com/courses/tdd-and-bdd-in-ruby/)
3. Day 3 - Advanced RSpec and Faking

Lesson 8 of 15

Duration: 25:44 [Watch on YouTube](https://www.youtube.com/watch?v=DIcPcL1_8A0)

We will now learn new features and advanced ideas to help clean up your RSpec files. Things like Subject, Let, specify, and more.

## In this lesson

Roy Osherove refactors the [string calculator](https://osherove.com/tdd-kata-1 "TDD Kata 1 - String Calculator (osherove.com)") specs, which have become long-winded, with subject, which by default is an instance of the described class, and lets for the [fake](https://livebook.manning.com/book/the-art-of-unit-testing-second-edition/chapter-4#ch04lev1sec2 "The difference between mocks and stubs (The Art of Unit Testing, 2nd ed., ch. 4)") logger and web service that can be overridden in a specific context, such as a logger that throws. He uses specify where the code says enough without a string and defines small methods such as adding so that each action is defined in one place. He notes a trade-off between the [readability](https://livebook.manning.com/book/the-art-of-unit-testing-third-edition/chapter-9 "Readability (The Art of Unit Testing, 3rd ed., ch. 9)") of the documentation report and of the code, and explains that its fits when a single action changes several attributes.

## Transcript

2,504 words

[\[00:03\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=3s) So what we're going to talk about now is a little bit about how to work a bit more effectively with [RSpec](https://osherove.com/blog/2013/3/29/acceptance-frameworks-vs-specification-apis.html "Acceptance Frameworks Vs. Specification APis (osherove.com)") because up until now we just use the most basic aspect of RSpecs, most basic aspects of our spec and our specs are becoming very very long- winded. You have a lot of a lot of text and very little content and it's actually make them making them a bit less readable. So I want to show you some tricks that you can do with RSpec to make the code a bit more readable and hopefully to ease some of the pain.

[\[00:34\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=34s) So what I'm going to do now is I'm going to try to refactor a little bit of of of the of the current spec that we have. And the first thing that I want to show you is that we we have the idea of something called subject. subject. Subject is a special word in RSpec and it basically defines a shortcut that we can use. By default the subject is whatever we describe

[\[01:08\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=68s) In the under the describe thing. So if we have used the let so far right we said let calc and then we say [string calculator](https://osherove.com/tdd-kata-1 "TDD Kata 1 - String Calculator (osherove.com)") new we wanted to do that well subject is kind of like that but it automatically defaults to having this type of code. So we can say subject if we actually just remove this whole line we get it by default.

[\[01:42\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=102s) So if string calculator didn't have any dependencies subject would there would be a method subject that referenced an instance of already mu up string calculator for each test. Okay. Now why is that important? because the word it and subject can be used synonymously. So you can actually say something like like this

[\[02:13\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=133s) I can say I can define subject here and say subject let's see maybe we can do something a bit more Okay. So if I decide that subject is at the top I'm going to say subject it can't be just simple new string calculator. So subject is

[\[02:44\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=164s) A string calculator new with a logger and a web service. Now what's cool about subject is that it it is lazily evaluated just when it's called and we can actually control the values of logger and web service that will be mued up for each subcontext if we want to. So we can go ahead and say that let's let

[\[03:19\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=199s) Logger to be a [fake](https://livebook.manning.com/book/the-art-of-unit-testing-second-edition/chapter-5#ch05lev1sec2 "Dynamically creating a fake object (The Art of Unit Testing, 2nd ed., ch. 5)") slow logger and that means that the logger in here will actually get its value from here. Okay, we can do the same for web service. Web service will be a fake of

[\[03:50\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=230s) Web service class. So that means that in these three lines we've defined the subject that is the subject of our test and its two dependencies right there in a very very explicit way. We can try to get rid of this

[\[04:21\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=261s) We don't need calc anymore but we call it right. So what we can do instead is we can give a name to our subject and say let's call it calc from now on. So now it can either be called through it or through subject do something or through calc do something. they all point kind of to the same thing. So here's a context with a logger. We don't need the mock logger anymore because it's already built in to the string calculator here.

[\[04:53\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=293s) Okay, we don't need to instantiate the string calculator. We just need to call add. Okay. And we should be able to just call the logger directly and verify. Oh, this is the the fake logger. So, we should be able to say that logger should have received, right?

[\[05:24\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=324s) And for now, we can say any args. Any ars is a shortcut in LOIUS that allows you to basically have any amount of arguments for example two and if tomorrow it's three it still passes and any value to each to each parameter okay let's see so that becomes a bit shorter and this allows us to let's see

[\[05:54\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=354s) Okay so we get a name error no such thing as a fake logger because we deleted the fake logger some other test are using it. So that's the error we're getting from another test. It's from line 24. So it's over here. You see this? We don't need fake logger anymore. But this actually passed. Okay. So you see we got rid of a lot of repeating code by having all this happen.

[\[06:27\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=387s) Now if we wanted to we can say let with call this a band and this basically tells RSpec that this the thing inside the curly braces gets executed like the before each test if you want to run a new instance before each test because by default the the value is lazily evaluated once and then saved.

[\[06:57\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=417s) Memoise it's called. It saves the value and then it gives that value to each new test but the state of the value is the same. It's not it doesn't change over tests. It's almost like it's serializing the value and then giving a value of that serialization to each spec. Anyway, we don't need the fake logger but we do want to configure the logger here to throw an exception. Right? So, how do we do that? Well, we can just use another let

[\[07:32\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=452s) And here we can just reset the logger to have to be called. So let logger to be a fake slow logger with the right method. Having a proc that raises a bam

[\[08:02\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=482s) Script. So what's going to happen now is that this overrides the global logger that we've set and will be injected into this line. So the logger from here is going to be using the logger from here at the context of this. So for that specific context we can just override the specific inputs into what is basically a function.

[\[08:36\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=516s) Okay. So we don't need to tell it that it will throw. We don't need to say new. We can just say cal.add add and we can say that web service should have received

[\[09:06\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=546s) Was it notify notify with any arcs. That's taken care of. So now we have this

[\[09:37\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=577s) Belongs here like this. You can say with the logger that throws we can put the left right up here so that it's connected to the context. right or web service and this is from line 26. Let's try that again. Line 26 in code spec.

[\[10:24\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=624s) Let's see. So undefined method write for web service. This is in the rescue part. I might have multiple web service classes here because of the demos. It's catching the wrong one. But if we only have one, it's usually much easier. Now what about this context of negative numbers? Let's try to deal a bit with this. Can we make this a bit more readable?

[\[10:57\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=657s) What if we said that? What if we said all this for negative numbers? Instead of doing that, we can say specify specify that you expect

[\[11:52\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=712s) So when we don't want to describe with a string when the string just feels like it's not needed because the text pretty much exemplifies what we want to have, we can just use specify as a short. Okay. And the same here we can just do that three times and have minus one 2 - one - 2 and get rid of all these.

[\[12:24\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=744s) So that's starting to look kind of nice, right? I hope. you write zero. >> Sorry, >> how the output is >> it's the same output basically. >> It's the same output. It's the same exact thing when you say it and then a string. It's the same as specifying it without a string.

[\[12:56\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=776s) But the expectation is that caulk add was supposed to raise an error. Okay. should raise exception. That's what it looks like. So, it looks a bit less nice. >> It definitely looks less nice in terms of a report. And that and and there's always a trade-off with these things. When you start stop using the strings, you start relying on the framework to start to parse what it is you're trying to do. There's always a trade-off between the [readability](https://livebook.manning.com/book/the-art-of-unit-testing-second-edition/chapter-8#ch08lev1sec3 "Writing readable tests (The Art of Unit Testing, 2nd ed., ch. 8)") of the doc report and the read readability of the code.

[\[13:30\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=810s) Unfortunately, one thing we'll see later in this course is that we can use higher level constructs like cucumber to have the documentation that we want and still drive these kinds of tests with different ways. So but I want you to to practice to in making things a bit more readable and [maintainable](https://livebook.manning.com/book/the-art-of-unit-testing-third-edition/chapter-8 "Maintainability (The Art of Unit Testing, 3rd ed., ch. 8)") in the specs. Now we're not done yet. This is just an example. Okay, what do we do with a single number?

[\[14:03\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=843s) Remember I said that we have that expect that method, right? What if we said that we can say what if we we can do subject just for this context and say the subject is

[\[14:48\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=888s) And sorry, what if we said this def

[\[15:24\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=924s) Or specify adding two five. What happens? See, expected five but got two. I can now have a much more readable way of saying

[\[15:54\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=954s) That with one set expect one. I can al of course specify calc add to should equal to but I find that this is one step nicer and I can get rid of that stuff and and now suddenly context of adding a single number or adding I can define adding at the top of the describe because it's reusable then I can use that

[\[16:25\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=985s) Expect adding like this I can use that also I can reuse use that. So I can define this at a higher level, move it away and then reuse that. So things are more are easier. Then I can of course do the same things like here handling two numbers. Then I can specify one and two should equal three. One, two, three should equal six.

[\[17:08\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1028s) And suddenly the hierarchy is starting to make a bit of sense. So one thing I like doing is that when I describe adding I define a method called adding just below it. Okay. And I define what the action looks like. If tomorrow the action changes I just need to change it to one place. Okay. But now I can actually say adding one and logger should receive. Same thing here.

[\[17:38\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1058s) I can do all these things. Okay, it's when you add one, you should get one. Now, this is actually a more interesting scenario that we haven't discussed yet, and I want you to actually do this.

[\[18:13\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1093s) I wanted to add a feature that has a calculator. Sum. So the feature is that it returns the last sum from the last operation made or form the last operation made. So I add one and then I check last sum. Okay. Now if I am using subject correctly, I can make things much much simpler or much much more readable. I I might be able to do something like this.

[\[18:45\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1125s) I can define the subject. Actually the subject is already calculated right. So I can say not sure. Okay. I can say that the subject

[\[19:18\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1158s) So here's what I'm trying to do. So I'm thinking out loud how to do this. What I would like to do is to use the special way of using it. So I can write something like this. It or its should equal one. Now this is a special construct because it is the subject.

[\[19:50\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1190s) Whatever is in the subject I can then assert on things on attributes of the subject. So I can say that subject do then I can say

[\[20:21\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1221s) Calc add one return the calculator that would make sense for this one but then I wouldn't be able to have multiple verifications of multiple attributes. I would have to repeat the subject in multiple cases. So it doesn't make sense to use it in this type. But when does it make sense? When a single action changes multiple attributes, right? You create a new person like the subject is creating a new person. Then you might say multiple its.

[\[20:52\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1252s) Its first name should equal George. Its last name should equal blah blah blah. And each one of them is running in its own little delegate universe. So if one of them fails, the other one still run. That's one of the coolest things about it. Okay. So maybe we can just try and do this specify that

[\[21:23\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1283s) Adding let's see I don't I I need to find a way to do this so that it there is only one action to do. So I can say let's define a method that says add and get last sum. It says count addut

[\[22:13\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1333s) So now I can say that add and get less sum should and get the sum of one equal one. Then I can do the same thing and say when you get back one and two and the last action sum should be three. Make sense? I can also say but what's the default?

[\[22:46\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1366s) Specify that well the default I can say actually it's last sum should by default equal zero because no action was performed make sense I can get rid of these things so it's just an example of how you would get around and get rid of things that you don't like.

[\[23:26\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1406s) Okay, here I can say that specify adding an empty string should equal zero. Whoa, I probably messed something up there. Not enough. We'll figure that out.

[\[24:04\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1444s) Come on. Okay, never mind. I think you get the idea. I won't bore you with any kind of running errors, but the point is that I want you to try to u start to use the idea of subject and let and overriding lets in different places. And what you end up with hopefully is something that is much much more readable. And instead of having the its you can you can well you can actually use the its here when they make sense.

[\[24:34\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1474s) It calls the web service and then the web service should have received notify. We can do many different things. For example, we can put the web service in the subject and say that it should have received notify. Okay, as an example, here's what it might look like. This is a different file context with a logger that throws. So let logger do something that throws bam

[\[25:05\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1505s) Make the subject the web service and then it should have received notify. Okay questions? Okay. So before moving on with the rest of the exercises from yesterday, I want you to try to clean up and see basically play like it's u like play-doh with the RSpec syntax and see what you end up with, what you like and where you don't like things, which constructs you like and see if you can clean it up a bit.

[\[25:42\]](https://www.youtube.com/watch?v=DIcPcL1_8A0&t=1542s) Okay.

## Related

- [Keep tests DRY](https://livebook.manning.com/book/the-art-of-unit-testing-third-edition/chapter-8#sigil_toc_id_161) · The Art of Unit Testing, 3rd ed., ch. 8

    The 3rd edition's section on keeping tests DRY, the goal of moving the calculator, logger and web service into subject and let.

- [Making your tests withstand design and interface changes - remove code duplication](https://osherove.com/blog/2005/4/10/making-your-tests-withstand-design-and-interface-changes-rem.html) · osherove.com

    Roy's post on putting object creation in one helper so a design change does not break many tests, as the specs here define each thing in one place.

- [Unit test readability should not come in place of maintainability - they go hand in hand](https://osherove.com/blog/2005/7/28/unit-test-readability-should-not-come-in-place-of-maintainab.html) · osherove.com

    Roy's reply on the trade-off between hidden setup and duplication in tests, the readability versus maintainability balance discussed here.

### Also linked in this lesson

#### The Art of Unit Testing, 3rd ed.

- [Readability](https://livebook.manning.com/book/the-art-of-unit-testing-third-edition/chapter-9), ch. 9
- [Maintainability](https://livebook.manning.com/book/the-art-of-unit-testing-third-edition/chapter-8), ch. 8

#### The Art of Unit Testing, 2nd ed.

- [The difference between mocks and stubs](https://livebook.manning.com/book/the-art-of-unit-testing-second-edition/chapter-4#ch04lev1sec2), ch. 4
- [Dynamically creating a fake object](https://livebook.manning.com/book/the-art-of-unit-testing-second-edition/chapter-5#ch05lev1sec2), ch. 5
- [Writing readable tests](https://livebook.manning.com/book/the-art-of-unit-testing-second-edition/chapter-8#ch08lev1sec3), ch. 8

#### osherove.com

- [TDD Kata 1 - String Calculator](https://osherove.com/tdd-kata-1)
- [Acceptance Frameworks Vs. Specification APis](https://osherove.com/blog/2013/3/29/acceptance-frameworks-vs-specification-apis.html)

[Previous lesson Using Bogus](https://courses.osherove.com/courses/tdd-and-bdd-in-ruby/using-bogus/) [Next lesson Bogus and Class Methods](https://courses.osherove.com/courses/tdd-and-bdd-in-ruby/bogus-and-class-methods/)


---

## About the author

**Roy Osherove**: Senior Solutions Architect at AWS working on AI for production and AI-driven development; author of The Art of Unit Testing and Elastic Leadership, with about 20 years of consulting and training on unit testing, TDD, team leadership and continuous delivery.

### Sites

- [RobotPaper](https://robotpaper.ai/): This blog: AI patterns and anti-patterns, AI and coding agents, and engineering leadership.
- [osherove.com](https://osherove.com): Roy's personal site. Author of The Art of Unit Testing and Elastic Leadership; consulting and training on unit testing, TDD, team leadership and continuous delivery, plus about 20 years of blog posts.
- [The Art of Unit Testing](https://www.artofunittesting.com): The Art of Unit Testing, 3rd Edition (Manning): readable, maintainable, trustworthy unit tests, plus TDD workshops in C#, JavaScript, Java and Kotlin.
- [5whys.com](https://www.5whys.com): Roy's writing on software team leadership: self-organizing teams, surviving chaos, learning mode and the Elastic Leadership model.
- [Pipeline Driven](https://pipelinedriven.org): Continuous delivery and DevOps practices: build patterns, pipeline-friendly testing, DevOps metrics and enterprise DevOps.
- [Elastic Leadership](https://www.elasticleadership.com): Elastic Leadership, Roy's framework for software team leaders (survival, learning and self-organizing modes).

### Social

- X: https://x.com/royosherove
- LinkedIn: https://www.linkedin.com/in/osherove/

### Contact

- Contact form: https://forms.gle/jQSx5KoXvrVA1JCK7

### License

Licensed under CC BY 4.0 — reuse, quote and adapt with attribution (Roy Osherove, link to the original page). License: https://creativecommons.org/licenses/by/4.0/
