While the earlier versions had the perfectly fine unit testing framework Test::Unit built right in, Ruby 1.9.x and up come with MiniTest as part of the standard library. Not only is MiniTest a drop-in replacement for Test::Unit (mostly, you may need to make some changes to your tests in some cases), it also adds a number of welcome additions. MiniTest is also gaining quite a bit of acceptance, becoming the de-facto default testing framework for Ruby and Ruby on Rails projects. Is this is enough to sway you from larger frameworks such as RSpec?
What is Test-Driven Development?
A unit test is a pass/fail method that ensures a method, piece of method, class or entire subsystem of your code functions are expected (or fails as expected). Test-driven development is an agile development methodology where unit tests become first class citizens, and in fact drive development of the system. Instead of writing tests after the fact, a kind of "appease this requirement" kind of task, tests are written first by those that adhere to strict test-driven development. By writing tests first, this both ensures that all aspects of the program is tested, as well as forcing a consistent process for writing code.
But why test at all? Software has been written for many years without any kind of tests, why start now? It hasn't been until recently that we've seen test-driven development being used seriously by anyone other than extreme programming (AKA XP, a rather extreme or at least radically different development methodology), but with the rise of dynamic programming langauges, TDD has seen more usage. Firstly, many bugs that would be caught by your C, C++ or Java compiler (as incorrect type, wrong number of function arguments, etc) are not caught by Ruby, or more accurately are not even errors in Ruby. You could say that everything is subjective in Ruby, what anything means depends entirely on the context it is used. Only by skill and careful programming do Ruby programs even function. But if you were to introduce an interaction that the programmer did not foresee, or the programmer makes a simple mistake that only works in most cases, this is a bug that can slip through to release. And of course future modifications by forgetful programmers, or programmers unfamiliar with the task or codebase can break anything. By writing unit tests for all code, and insisting that all unit tests pass at all times, you can verify that the code functions as intended. This goes beyond fixing the lack of compile-time errors and strict function signatures and takes strides toward program verification.
Basic Assertions - At the core of any unit test is an assertion. An assertion declares a premise should (if the program is functioning properly) be either true (using the assert methods) or false (using the refute) methods. Each of the assertions of refutations are the core of all unit tests.
More Assertions - While the two basic methods (assert and refute) can be used in all situations, there are more semantic methods that can be used as shorthand for more convoluted constructions, as well as add clarity for anyone reading the unit tests. MiniTest comes with a small library of assertions you can use.
Specifications - The basic assertions are fine, but there are also specifications. Technically the same thing as assertions, they have a vastly different syntax. Instead of a boring method call, they're methods on the objects they're testing. For example, instead of saying assert_empty some_array, you can say the more readable and Ruby-like some_array.must_be_empty.