This lesson is intended for 2-3 students to work through together. Learning collaboratively likely means moving through content slower, but also should result in learning more thoroughly. In addition to working together, this learning environment is new for all students - take time to learn about strategies your partner uses, tips they have, etc. as well as share your best practices!
To make sure you are set up for success, get yourself prepared for a pairing-like environment. Fill your water bottle, put your phone aside, and be ready to fully engage.
As you work through this lesson with your partner(s), focus in on your communication, exercising patience, and making sure all students complete the lesson with a similar level of understanding.
- Explain what a test is (in software development)
- Read an
rspectest and explain what it is asking for
- Write simple Ruby classes that meet requirements of pre-written tests
- Develop new learning strategies and practice communication by learning collaboratively
- Test Driven Development
- testing framework
Share with Partner
What do you do with the Vocabulary sections? How do you ensure you can fluently define and use all terms listed, by the end of the lesson?
In software, it is common to write automated tests to verify that our code behaves the way we want it to and doesn’t have any negative or unexpected side affects on any other part of a project. These tests are usually written in the same language the code itself is, with the help of a tool that is usually categorized as a testing framework.
There are many ways a file structure can be designed when there are many files in a project. A common convention, and one you’ll use in Mod 1 is illustrated:
project_name |-lib |-name_of_class.rb |-name_of_class1.rb |-spec |-name_of_class_spec.rb |-name_of_class1_spec.rb
(Note: The directory and file names do not start with
|-; that is just a way to notate the structure.)
rspec is a tool, classified as a testing framework, that allows us to write automated tests that will test our Ruby code. Just like we must write Ruby exactly as it’s intended to be used, we must carefully use the syntax and methods available within
rspec. The official
rspec documentation may at first seem dense; it has much more than what you will even get into in Mod 1, but it’s great to be aware of and start getting comfortable reading if you need a resource during or after this lesson.
While navigated to the project that is applicable, run this command in the Terminal to add the
rspec framework to that project. This command only needs to be run once per project.
$ gem install rspec
The first two lines of every test (or spec) file should be:
require 'rspec' require './lib/<name_of_class>.rb'
To run a test, or spec, file, in the Terminal:
There are times when you need to follow directions exactly, and times when you might need to adjust to add in custom information. In the previous examples, we can infer that
name_of_class_spec is not actually a file name, but the documention is intending to show the reader that the last part of the file name should be
_spec, preceded by the name of the class the test file will be testing.
Syntax and Anatomy of an
A series of code snippets is provided to show a progression of a test file being built. In Mod 0, you do not need to be proficient in writing tests; this progression is shown to help you focus on each piece with a paired explanation.
The code snippet that follows shows the skeleton of an
rspec test. The class it is testing is named
Student, and lives in a file with the same naming convention.
rspec and the code file, a
describe block is opened up, where
rspec expects the class name. The
end open and close the block, similar to other Ruby structures. The code snippet that follows is not enough to test any code; but it’s the first step:
# student_spec.rb require 'rspec' require './lib/student' describe Student do end
In the next code snippet, one test has been added inside of the
describe block, to test a very small thing - this test verifies that when an object instance is created, it is actually an instance created from the class it should be created from.
describe block contains:
itstatement - a String that uses plain English to describe what it (the test) tests
- Definition of a variable that stores a student object
- An assertion written with
# student_spec.rb require 'rspec' require './lib/student' describe Student do it 'is an instance of student' do student = Student.new('Penelope') expect(student).to be_a Student end end
The final snippet adds a test (in a new
it block) that checks if a student object instance has a name attribute that matches the value that was passed in upon creating the object instance:
# student_spec.rb require 'rspec' require './lib/student' describe Student do it 'is an instance of student' do student = Student.new('Penelope') expect(student).to be_a Student end it 'has a name' do student = Student.new('Penelope') expect(student.name).to eq 'Penelope' end end
The following code snippet provides an annotation for each line of this same file:
# ensures the rspec testing framework is available for use in this file require 'rspec' # allows the spec file to read the contents of the student file require './lib/student' # start of describe block; one per class/test file describe Student do # start of it block for an individual test # the string should briefly describe in plain English what is being tested it 'is an instance of student' do # create a student object instance student = Student.new('Penelope') # assert that the student is from the Student class expect(student).to be_a Student end it 'has a name' do student = Student.new('Penelope') # assert that the student has a name property which matches what was passed in expect(student.name).to eq 'Penelope' end end
The code that follows would allow the previous tests to pass (which should live in the
class Student attr_reader :name def initialize(name) @name = name end end
With your partner, decide on the best way to complete this activity: Driver-Navigator, both complete independently then discuss, etc. It may be helpful to skim the activity before making that decision.
Follow the directions to set up a small project that uses
- Create a directory called
- Install the
rspecgem using the command noted earlier in the lesson
- Create two directories:
- Create one file inside of each of the new directories:
- Copy and paste the code for the Student class and the two tests that are provided above, into the appropriate files
rspec spec/student_spec.rbin your Terminal
- Delete the
attr_readerfrom the Student class and re-run the tests; observe what happens
- Delete the entire
initializemethod from the Student class and re-run the tests; observe what happens
- Delete the entire Student class and re-run the tests; observe what happens
- Bring back all the original code into the Student file and re-run the tests to ensure they now pass
Challenge: Write a new test, that checks that the student has a dynamic age property. Write the code to make the test pass.
Test Driven Development
Test Driven Development is a common process for writing software. It entails writing the tests before the code, then using the test to guide the developers while writing the actual code. This lesson will provide some exposure to the process, and the Mod 1 curriculum will dive deep into it and require it of students.
When provided the test file that follows (the same one we’ve been looking at in previous examples), one can turn that code into directions that inform what should be written into the
require 'rspec' # write your code in a file named student require './lib/student' describe Student do it 'is an instance of student' do # since a student object is being created from a Student class, # write a class named Student # ALSO - since an argument is being passed to Student, the initialize method needs to accept one student = Student.new('Penelope') expect(student).to be_a Student end it 'has a name' do student = Student.new('Penelope') # since we need to call the name attribute and get back the string that was passed in, # we need an attr_reader for the name attribute expect(student.name).to eq 'Penelope' end end
The comments in the file can help a developer write an even more accessible specification:
- Write a class named Student, in the
- The class should have one dynamic attribute named
- Use an
namecan be read
With that, the following code can be written to satisfy the tests:
class Student attr_reader :name def initialize(name) @name = name end end
Practice Reading Tests
Read the test in this file and write out a list of human-readable, clear directions you could read aloud to someone you are pairing with in order to pass the tests. One of the tests does push you to apply some learning that was not explicitly covered in this less - that was intentional! The goal is not to be perfect or perfectly correct; it's to push you to apply some other knowledge and have a technical discussion with your partner.
Check For Understanding
Each partner should complete this independently. It is ok to consult one another if needed!
Create a new directory with
test directories inside. Use the test file that was provided in the previous activity, and write a class that satisfies those tests. Use your Git Workflow, make a GitHub repository and push your completed work up.
Each student should submit their own repo to the submission form.
Mod 0 Extensions
Your Mod 1 instructors have created this repository to give you something to work on in between Mod 0 and Mod 1. Nothing is required; but students in the past have found it as helpful and aligned practice during the “down time” before Mod 1. Have fun!