Search code examples
ruby-on-railsminitestteardown

Rails-How to use MiniTest's Teardown Method


I have been looking around the internet for a long, frustrating, while, and I'm still quite confused as to what the purpose of the teardown() method is in MiniTest and how it should be used.

The basic gist I have is that it is 1-run after each test, and 2-undoes things that were done during the test in order to allow future tests to run in a clean environment.

However, I am unclear on the nature of things it needs to undo: Does it need to empty the DB? Reset class variables? etc.

I am also unclear on whether the method is supposed to be explicitly filled out or not. I have found many examples where teardown() is completely left out of the example.

(My best guess is that there is a super-method teardown that runs automatically and takes care of certain things. That would explain why it is often left out, and would also explain why some things are reset in a given teardown() method and some aren't. But I still don't know which things are and which aren't.)

In short:

Does teardown need to be explicitly created? In what circumstances would it need to be overwritten and in which wouldn't it be?


Solution

  • The simplest answer is that you use #teardown in every test but you don't need to worry about it. Similar to the Rails lifecycle, there is a Minitest lifecycle. There are hooks to inject logic and behavior to be used by your tests. The main one in Rails tests is the database transaction. Each test that uses ActiveSupport::TestCase runs in a database transaction. The flow is like this:

    1. Create the database transaction (Minitest::Test#setup)
    2. Run your test method (MyTest#test_something)
    3. Rollback the database transaction (Minitest::Test#teardown)

    It is somewhat common for folks to use #setup to create objects for use in tests. After the test method completes the test object is garbage collected, so most folks don't use #teardown to clean up after the test. Because of this #teardown is typically a more advanced feature that you don't normally use when writing tests. I see it used much more often in testing libraries that enhance Minitest.

    But there are times I do use #teardown in my tests. Here is an example of when I might use it.

    require "minitest/autorun"
    
    class Foo
      def initialize namer
        @namer = namer
      end
      def name
        @namer.name
      end
    end
    
    class FooTest < Minitest::Test
      def setup
        @namer_mock = Minitest::Mock.new
        @namer_mock.expect :name, "foo"
        @foo = Foo.new @namer_mock
      end
    
      def test_name
        assert_equal "foo", @foo.name
      end
    
      def teardown
        @namer_mock.verify
      end
    end