Ruby
In-spec-tion
Summarized using AI

In-spec-tion

by Jon Rowe

In this presentation from RubyConf AU 2016, Jon Rowe, a maintainer of RSpec, dives into the inner workings of RSpec, a popular testing library for Ruby. The talk aims to demystify RSpec's components and reveal how they function together to create a powerful, descriptive testing framework.

Key Points Discussed:

  • Introduction to RSpec: RSpec is a testing library that offers a more expressive alternative to conventional test unit styles found in Ruby and Rails.

  • Core Components:

    • RSpec Core: The foundational part that includes the test runner, configuration, and example group definition.
    • RSpec Expectations: Adds descriptive syntax through matchers to define expectations in tests.
    • RSpec Mocks: Supports creating test doubles and stubs for object communication, enabling controlled testing.
  • RSPEC with Rails: A discussion on RSpec Rails, which provides conventions for integrating RSpec into Rails applications.

  • Example Group Structure: Rowe explains how example groups in RSpec differ from traditional tests by allowing shared state and encapsulation of functionality. They are structured as a hierarchy of classes, supporting Behavior Driven Development (BDD) principles.

  • Execution Process: He describes the roles of different components when running RSpec, like the 'world', configuration, reporter, and runner. The interaction of these components establishes a well-structured testing environment.

  • Expectation Syntax and Matchers: The talk covers how to define expectations using the expect method and highlights the significance of matchers in checking value consistency.

  • Integration of Mocks and Expectations: Jon emphasizes the interplay between RSpec Mocks and Expectations, ensuring a cohesive design that maintains RSpec’s structure and functionality.

  • Conclusion and Q&A: Rowe concludes by encouraging questions from the audience and reassuring that the complexities of RSpec are shared among users, promoting ongoing dialogue about RSpec's capabilities and Ruby testing at large.

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.
Explore all talks recorded at RubyConf AU 2016
+11