Testing is undeniably an important part of web development. Continuing on from my last blog post, I am going to give more information about how to write tests with Ruby on Rails in this post. This post will be easier to understand if you read my last one, Intro to Testing With Rails. This one picks up where I left off, and explains more of the structure of the testing framework that Rails provides.
But before I get into that, I’ll talk a bit about the mindset a developer should have when writing tests. Sometimes it can be hard for a developer to write tests because you need to have a different mindset from when you are creating parts of your application. When writing out the features of an app, you want to focus on all ways your app will work. But, when writing tests you have to think about all the ways your app could break. Sometimes it can be hard to think about breaking your app when you worked so hard to make it function the way you want it to, but you need to think in this mindset to write good tests.
Now back to Rails testing. One thing you should have is a separate database specifically for testing. Most of the parts of the your application are going to interact heavily with a database, but when you are testing you are usually going to be writing bad data in an attempt to see if things break. Also, you will most likely be running the tests over and over again, and you don’t want all of the data you made in your tests to be added to the database multiple times. This is why we have a test database. Once again, Rails has already taken care of this problem for you. By default, every Rails app has three environments: development, test, and production, and there is a database for each of them. They are configured in
config/database.yml and created when you run
One way Rails uses the test database is with fixtures. Fixtures are sample data that Rails will automatically add to the test database each time your tests are run. Fixtures can be very useful because you don’t have to create a new instance of a model for every test you write, you can just reference one that’s already in your database. Fixtures are written in a file with a .yml file extension and they look like this:
# in fixtures/authors.yml rowling: name: J. K. Rowling age: 55 # in fixtures/books.yml harry: title: Harry Potter author: rowling
The authors.yml and books.yml files these fixtures are written in were generated when I used the
rails g scaffold commands. Whenever you generate a new model Rails will automatically create a new file for fixtures of that model (with examples) in the test/fixtures directory.
As you can see from the examples, there is a specific format to fixtures. Each is given a name (anything you want to call it) which is followed by an indented list of the model’s attributes followed by a colon and whatever value you want to give the attribute. Also, notice how the books fixture references the author fixture. This is completely valid and, just by writing
rowling, Rails will know that you are referencing the
rowling fixture in the authors.yml file.
Now, to use the fixtures in your tests you have to reference them like this:
authors(:rowling) or, to get a list,
authors(:rowling, :author_two) will return an array with two fixtures. Once you have a reference to a fixture, you can treat it the same as any other instance of the class, such as using any of the methods the class might have on the fixture.
This is an example of a passing test using fixtures: # in models/book_test.rb test "fixtures properly save to database" do assert_not_nil books(:harry), "book fixture did not save to database" assert_equal authors(:rowling), books(:harry).author, "book fixture does not reference author fixture" end
Now, so far I’ve only changed Rails-generated files in two folders in the test directory: models and fixtures. As I just explained, files in the fixtures folder are for creating sample data to run your tests on. In the models folder you write tests to test the methods in all your model classes using assertions. So, as yet, I have only written tests for my models in the models folder. But testing the behavior of your models is by no means sufficient to prove that a Rails app works as intended.You also need to test how a user can interact with the app. In other words, test the controllers and routing.
Testing you controller actions and what shows up on a web page uses a different system of writing tests using a gem called Capybara. In my next bog post on testing with Rails I will focus on how you can use Capybara to test a user’s interaction with web pages in a Rails app.