00:00:00.080
Hello, everyone! I hope I'm saying this right – 'Jingary'. Well, I actually did some research on that greeting before I got here.
00:00:05.920
We had the awesome opening show this morning, which made me a bit terrified. I was going to say it wrong, but hopefully I've said it right now.
00:00:10.960
So, I'm Jon, as Mel and Liam, aka Melliam, have introduced me. I am one of the maintainers of a little project called RSpec, and I have the pleasure of talking to you about it today.
00:00:16.160
For those of you in the room who might be new to Ruby or Rails, RSpec is a testing library that focuses on providing a more descriptive language for tests than some of the traditional test unit style libraries. Rather than having a class with test methods like you might find in a test unit, RSpec offers a more trivial setup followed by a single test format.
00:00:28.560
At its core, RSpec allows for the creation of specs that can be straightforward yet expressive.
00:00:36.719
As a trivial example, I could describe Einstein's theory of relativity. That's just a simple analogy for you all since I needed to pick something basic to work with.
00:01:04.879
But what is RSpec under the hood? To start, RSpec is not a single piece; it’s actually several isolated components that fit together to form one cohesive tool.
00:01:18.000
The main component is RSpec Core, which contains the basic parts such as the runner, configuration, and allows the definition of your examples and example groups. Then we have RSpec Expectations, which sets up the matchers and expectations adding another level of descriptive syntax. Additionally, there's RSpec Mocks, which supports test doubles and stubs, enabling us to set expectations on messages passed between objects.
00:01:42.240
Each of these components can function together or independently. It's possible to utilize RSpec Core by itself, mix it with other libraries like Shoulda Matchers, or use RSpec Mocks in conjunction with Test Unit assertions.
00:02:06.240
One question you might ask is about RSpec Rails. RSpec Rails is indeed a bit different because it consists of conventions for using RSpec with Rails. Essentially, it's the Rails way of testing using RSpec.
00:02:36.800
Now, let's take a moment to dive into a sample spec to understand how RSpec actually works. We'll look again at our simple example involving relativity. The first step is to rewrite this as a core RSpec spec. Not much changes; we mainly remove some of the syntax sugar and focus on the essence that states 'E must equal MZ squared'.
00:03:13.200
In this spec, the first thing we do is create an example group class. Here, we're defining a subclass of example group that RSpec will name 'Einstein's Theory of Relativity'. We're defining some instance methods that utilize a bit of syntactic sugar and magic behind the scenes to store values for us. Essentially, it becomes a class with a method definition. The hooks in RSpec are a bit more magical than in traditional test unit styles. They are registered in a way similar to Active Record callbacks, though they're handy nonetheless.
00:04:25.759
As we set up example groups defined in our RSpec files, how do we run them? This is where RSpec Core comes into play. There are several vital components involved in making RSpec work, including the world, configuration, reporter, and runner.
00:04:55.120
The 'world' is an unavoidable piece of global state that tracks all your example groups, as well as ordering strategies, filters, and similar items. If you're using RSpec programmatically, you're able to create this yourself, although most users will interact with a single instance provided for the command line.
00:06:00.479
Configuration holds all the configuration options, which are quite numerous! It manages the process of loading spec files into the world during execution, and is responsible for filtering and organizing elements, as well as setting up formatters.
00:06:14.479
The reporter takes instructions from the runner and communicates with various interested parties. It's mostly about notifying formatters and we encourage users to create their own pieces of code that utilize the reporter for lifecycle events, similar to instrumentation in Rails.
00:06:38.800
The final component is the runner which gets invoked when you run RSpec from the command line. It creates a world, takes configuration options, passes them to configuration, sets everything up, and starts executing your example groups. You might wonder, why do we refer to example groups rather than just tests? This architecture allows for sharing state across examples or reusing functionality. Instead of defining one class for all tests as in traditional testing, RSpec allows us to define a class per test, which encapsulates the individual examples without carrying specific context along.
00:07:51.520
The runner processes each of the hooks, then runs the example groups, executing the associated code blocks and managing the results. There are several additional structures in place to ensure exceptions are caught and managed, making the testing process robust.
00:08:50.880
At the core of RSpec, when you write a spec, you're actually creating a hierarchy of example group class definitions. Sub describe and context blocks are effectively subclasses of parent example groups, which is crucial for isolating behavior.
00:09:04.800
While you might wonder why this approach is preferred, it ties back to RSpec’s history with Behavior Driven Development (BDD). Our goal is to provide readable specs while maintaining control over how example groups are defined. Even if you could write classes directly, RSpec’s abstracted structure allows for enhanced functionality like metadata and example filtering.
00:10:31.120
We make it easy to include and extend functionality with additional modules to bring in special features you may need. Expectation syntax is where the next part of RSpec comes into play.
00:11:04.000
Let's look at the syntax of expectations. The 'expect' method is what we utilize to define our expectations. Both the 'expect' and 'should' syntaxes work similarly yet are targeted differently.
00:11:36.560
Matchers also play a crucial role. They are responsible for checking if a value matches another value. The methods implemented in matchers, like 'matches' or a failure message, are essential for RSpec’s functionality.
00:12:02.160
Furthermore, RSpec Mocks can be used as a standalone library, allowing users to interact with double tests without relying on expectations from RSpec itself, offering flexibility in how mocks function.
00:12:23.680
The integration between mocks and expectations is carefully managed, ensuring that RSpec maintains its rigorous structure and consistency.
00:12:45.560
As mentioned earlier, RSpec Rails is simply a thin wrapper organizing the Rails test helpers into RSpec’s framework, allowing seamless integration with Rails applications.
00:13:38.400
Most of the architecture in RSpec, as we explored today, allows for the separation of components like expectations and assertion tests. This flexibility is a key advantage to using RSpec, as it adheres to a straightforward compositional design.
00:14:35.680
With that, I have actually run out of slides, and I want to open the floor for any questions you might have.
00:14:56.000
It's possible we have a lot of time, so feel free to ask anything, even if it’s not directly related to my talk.
00:15:02.839
I appreciate everyone who uses RSpec. I welcome all questions about what we discussed or any other queries you have in mind.
00:15:36.360
As a final note, if you ever felt overwhelmed by the complexities of RSpec, please know that many people share that sentiment. Thank you!
00:16:00.000
I look forward to communicating further with all of you about RSpec’s evolution and your own journeys in Ruby testing.