Getting Started with MiniTest
Whet ever you may believe about testing practices; tests still provide some peace of mind and clarity in projects. Also; if you build a library for others to use, tests are a form of validation of your work and provide trustworthiness to your code. In the case of working with a large project that is without tests, many will have to deal with too much “state” to keep in mind. Our minds function best when we can simplify things; without tests though, we end up taking mental notes, experimenting, and debugging a LOT. So test as you may. Just know that testing it will give you credibility and clarity.
Test Setup
Both Bundler and Rails build new projects with MiniTest as the default test suite. So when starting a new gem you may simply type bundle gem my_new_gem . Then you can go into the folder and type rake test to see your first failing test (which is how you want to start). Likewise in Rails you type rails new my_project and the test directory is ready for content. Rails won’t have a failing test yet. First you need to add content to the project with its built in generators; which will generate the test files along with each thing you generate.
To add testing to a project that doesn’t have any test suite files for testing yet you can use Bundler on an existing folder. Run ‘bundler gem existing_project_folder‘ and then hit ‘n‘ and [enter] for every overwrite prompt.
The majority of this tutorial will focus around Rails. I suggest reading it even if you’re not using it for Rails as I will cover most of the same basics.
You may specify the file naming scheme yourself in the Rakefile with Rake::TestTask
Rake::TestTask.new do |t| t.libs << "test" t.test_files = FileList['test/test*.rb'] t.verbose = true end
By default the test files that get loaded start with the word test: test/test*.rb By following my spec instructions below the spec style file naming scheme will be used instead: test/*_test.rb
MiniTest Spec Style
I’ll be writing my examples in spec style. According to Ruby Survey Results the majority of Ruby developers use spec style testing. Setting up spec style testing with MiniTest is super easy. You just need to add the following require to your test/test_helper.rb file.
# test/test_helper.rb require 'minitest/autorun'
In some cases this may be a test/minitest_helper.rb file. And that’s all you need to do to enable spec style syntax throughout your MiniTest suite. Every test file will require ‘test_helper’, and everything should be smooth sailing from there.
Generate Spec Style
Now when Rails generates tests for each new feature you generate, it will default to test-unit style. If you would like it to generate spec style tests for you then you can do the following two configurations.
First we need a library that will enable spec style tests to be generated. I highly recommend the gem that covers most of the bases you’ll be using in your Rails project ‘minitest-rails-capybara’, but for what we need here ‘minitest-rails’ will suffice. So add it to your gem file in the groups development and test.
# Gemfile group :development, :test do gem 'minitest-rails' end
Run bundle and then add this to your config/application.rb file inside of where all of the configuration settings are.
# Use Minitest for generating new tests. config.generators do |g| g.test_framework :minitest, spec: true end
Now any time you generate a new feature in Rails it will create the baseline spec test for you.
If you don’t have the spec generated for you it’s pretty simple to just delete the test-unit style test and put in the spec code. Just remove the class code and add a describe block.
Rails Model Example
In your Rails project lets go ahead and make an example model.
rails g model Apple color:string rake db:migrate
This creates the test file test/models/apple_test.rb . If you go ahead and run ‘rake test‘ it will pass with 0 tests if you’ve used the test-unit style, or pass with 1 test for spec style. The spec style test generated will look as follows.
describe Apple do let(:apple) { Apple.new } it "must be valid" do apple.must_be :valid? end end
The Basics of Spec Syntax
describe is an identifier for a block of tests that will be grouped together. It is also a block that keeps state within its own scope and available to its methods; such as let. let is a memoize type of method, and it’s a lazy one. let takes a symbol as an argument which will be the variable you’re defining (technically a method). The block you hand let is what will be assigned to that variable. The variable will be available to each of the tests within the same describe block.
it is a test. You hand it a string to describe what the test is about and then give it a block of code to test. In that block of code you will use a, or many, Minitest expectation method(s) to evaluate whether the test meets the condition you’ve set. These are called assertions in your test results.
A few examples of Minitest expectations include:
describe ExistingObjectToTest do let(:example) do [1,2,3] end it "must contain valid values" do example.must_include 2 example.wont_include 4 end it "must equal" do example.must_equal [1,2,3] end it "must evaluate itself to be the same as truth" do thing = true thing.must_be_same_as true end it "is the Object we expect it to be" do User.must_be_instance_of Object end it "must be nothingness itself" do thing = nil thing.must_be_nil end it "is now running on empty" do thing = [] thing.must_be :empty? end end
The must_be expectation method will evaluate boolean methods on your object so you can test with methods like :empty?, :present?, :nil?, or any other true/false self evaluating methods. For more expectation methods feel free to look up the RubyDoc on it MiniTest::Expectations . Each of these expectations belong inside an it block which will describe what the purpose of what those set of expectation tests are.
Hooks
You may also setup some code before and after your tests with hooks. In spec style you’ll use before and after hook methods.
describe SomeThing do before do # Create some stuff here before each test end it "works with the stuff created in before" do # some expectation/assertion end it "a fresh start on the before stuff to test" do # some expectation/assertion end after do # clean up stuff in-between each test end end
Other than that you can always include your own code right into your tests with include MyModule .
Master MiniTest
Now I’m a bit new to the Minitest scene myself so I’m recommending you to check out whom I believe is an expert on it; Chris Kottom. Chris Kottom lives in Prague, Czech Republic with his wife, Petra, and his two kids, Ema and Oskar. They like to travel and cook together, and the kids and he have been working on learning Three.js.
I asked him a bit about his journey into software development to which he replied “I spent the first years of my career doing Java and Perl programming mostly, also some sysadmin work. I started looking at Ruby on Rails in 2006, I think. By that time, I’d been working as a manager and architect for a few years and had just about given up on programming, but Ruby and Rails made me want to start doing it again, and I’ve been at it ever since.”
I further asked him how he came to MiniTest as his choice. To which he replied “The first time I really looked at it was about 2 years ago. Like a lot of developers, I wanted to be a better tester than I was, but I’d not had much luck getting there following the flavor-of-the-month testing frameworks that seemed like they kept coming. Unlike RSpec, which I was using on the last big project I was on, I liked the fact that Minitest was small enough to be its own documentation. When I had a question, I didn’t need to hunt around Stack Overflow or some rdoc to find an answer. I could just open the source and find out what was happening.”
Chris has just recently written and published his own book on MiniTest called “The MiniTest Cookbook“. It thoroughly covers MiniTest as well as the crucial building blocks for testing in Rails. The Appendix is packed with each MiniTest expectation, assertion, and hook, with code examples and brief descriptions to help really clarify their usage. I highly recommend getting yourself a copy of this book to both help you understand MiniTest fully and at the same time you will be supporting Chris, and his family, for his great contribution to the Ruby community. It is an enjoyable read.
Chris also writes on his blog from time to time and has already helped bring greater understanding of MiniTest to the whole online community. So if you’re really looking to learn MiniTest I can’t recommend him highly enough.
Summary
Testing isn’t that hard to do. All you really have to do is “get started” and then it’s one step at a time. MiniTest brings the best of both worlds by allowing you to test with both test-unit style code and spec style while maintaining a simple design which is easy to customize. You may like checking out the many different colorful output plugins available; You have from your basic colors, to rainbows, to emoticons, to even sound effects based on test results. And that just makes the vibe from testing your code all the better.
I may revisit the topic of testing with MiniTest in a future blog. Maybe some tricks I pick up along the way. Feel free to ask me any questions. But do yourself a favor and get the book.
I hope this was both helpful and insightful to you. Please share, I’d love to hear about them. Please feel free to comment, share, subscribe to my RSS Feed, and follow me on twitter @6ftdan!
God Bless!
-Daniel P. Clark
Image by Alejandro C via the Creative Commons Attribution-NonCommercial 2.0 Generic License.