maxitest

repository·master·Indexed 19 days ago

https://github.com/grosser/maxitest

An enhanced version of Minitest for Ruby that adds features such as `around` blocks, `let!`, `with_env`, and `context` aliases. It provides improved output handling with `capture_stdout` and `capture_stderr`, a `LineReporter` for focused failing tests, and restores global `.must_*` and `.wont_*` assertions. Additional utilities include thread leak monitoring via `Maxitest::Threads`, global test timeouts, `pending` and `xit` DSLs for skipping tests, and enhanced Interrupt signal handling for better backtrace visibility.

Tokens
4.2K
Snippets
21
Records
24
Agent score
67%

What's inside maxitest

  1. Basic Usage of Maxitest

    master

    To use Maxitest, require maxitest/autorun. It is fully compatible with standard Minitest describe/it syntax.

    require "maxitest/autorun"
    
    describe MyClass do
      describe "#my_method" do
        it "passes" do
          _(MyClass.new.my_method).must_equal 1
        end
      end
    end
    require "maxitest/autorun"
    
    # ... normal minitest tests ...
    describe MyClass do
      describe "#my_method" do
        it "passes" do
          _(MyClass.new.my_method).must_equal 1
        end
      end
    end
  2. Use implicit subject in describe blocks

    master

    Maxitest provides an optional ImplicitSubject module that automatically defines a subject using the class passed to a describe block. If you pass a class as the first argument to describe, and that class does not already define a subject method, Maxitest will automatically add a let(:subject) { args.first.new } definition to that class.

    Note: This feature is not included by default because it overwrites the standard describe method. To use it, you must explicitly include Maxitest::ImplicitSubject into Object.

    # To enable the feature:
    Object.include Maxitest::ImplicitSubject
    
    # Usage example:
    class MyClass; end
    
    describe MyClass do
      # 'subject' is automatically available and initialized as MyClass.new
      it "is the subject" do
        assert_instance_of MyClass, subject
      end
    end
  3. Use the LineReporter for focused failing tests

    master

    The Maxitest::Line::LineReporter is a custom Minitest reporter that identifies failing tests and prints a concise list of commands to rerun only those specific failures.

    When tests fail, it outputs a command formatted as either bin/rails test <file>:<line> (if a bin/rails executable is detected in the current directory) or minitest <file>:<line>. The output is colorized in red if the output is a TTY.

    This reporter is automatically integrated into Minitest via the Maxitest::Line::MinitestPlugin if the :include option is not present in the Minitest options.

    # The LineReporter is typically used via the Minitest plugin system.
    # It will automatically append itself to Minitest.reporter.reporters
    # unless you have already specified an :include option.
  4. How Maxitest handles Ctrl+C (Interrupt) signals

    master

    Maxitest enhances the standard Minitest behavior when a user interrupts a test run using Ctrl+C. Instead of immediately crashing the process, Maxitest captures the Interrupt signal and treats it as a regular error. This provides two key benefits:

    1. Backtrace Visibility: It captures the current backtrace, allowing you to see exactly where the test was stuck.
    2. Graceful Termination: It marks the test run as interrupted and skips all remaining tests in the suite, preventing a messy exit and ensuring that the test runner (especially in -v verbose mode) produces a clean report rather than crashing.
  5. Enable verbose backtraces in assertion failures

    master

    When running Minitest with the --verbose flag, maxitest automatically enables verbose backtrace formatting for assertion failures.

    When Maxitest::VerboseBacktrace.enabled is true, assertion messages are extended to include the full backtrace, joined by newlines and indented. This is achieved by overriding Minitest::Assertion#message and setting Minitest.backtrace_filter to Maxitest::VerboseBacktrace::NullFilter to prevent Minitest from filtering out stack frames.

    If you are using Rails, maxitest will also call Rails.backtrace_cleaner.remove_silencers! to ensure Rails' own backtrace cleaner does not hide relevant information during verbose runs.

    # Run minitest with the verbose flag to trigger this behavior
    # (Assuming maxitest is loaded in your test environment)
    # bundle exec ruby -Ilib:test test/your_test.rb --verbose
  6. Disable timeouts for a specific test file to enable debugging

    master

    If a test is timing out and you need to use a debugger (like binding.pry or debug), you can disable the Maxitest timeout mechanism for that specific test file by defining a method named maxitest_timeout that returns false.

    This bypasses the ::Timeout.timeout wrapper, allowing the test to run without being aborted by the Maxitest::Timeout::TestCaseTimeout error.

    class MyHangingTest < Minitest::Test
      def maxitest_timeout
        false
      end
    
      def test_something_slow
        # This test will no longer be aborted by Maxitest's timeout
        sleep 100
      end
    end
  7. Configure global must_* assertion loading order

    master

    To use global assertions like obj.must_equal, you must ensure the loading order is correct. If maxitest/autorun is required before maxitest/global_must, the global methods may not be properly associated with the current test instance.

    Correct Order:

    1. require 'maxitest/global_must'
    2. require 'maxitest/autorun'
    require 'maxitest/global_must'
    require 'maxitest/autorun'
  8. Prevent extra threads from leaking between tests

    master

    By including Maxitest::Threads in your Minitest tests, the library automatically monitors thread counts. It captures the list of running threads during setup and compares them during teardown. If any extra threads are detected after a test finishes, an error is raised: "Test left #{found.size} extra threads (#{found})". To prevent test interference, the library automatically attempts to kill any leaked threads in an ensure block.

    Minitest::Test.include Maxitest::Threads
  9. Troubleshooting minitest-reporters integration

    master

    If you use minitest-reporters and encounter "stack level too deep" errors, you can disable Maxitest's interrupt handling by setting the following environment variable:

    ENV["MAXITEST_NO_INTERRUPT"] = "true"

  10. Use context as an alias for describe

    master

    The context method is a semantic alias for describe, allowing for more expressive test grouping.

    describe "#my_method" do
      context "with bad state" do
        before { errors += 1 }
        it "fails" # ...
      end
    end
  11. Capture stdout and stderr separately

    master

    Maxitest provides capture_stdout and capture_stderr to capture output from standard streams individually. This is useful when you want to verify specific output without capturing both streams (unlike the standard capture_io).

    output = capture_stdout { puts 1 }
    _(output).must_equal "1\n"