{"id":13877577,"url":"https://github.com/rubocop/minitest-style-guide","last_synced_at":"2025-04-08T17:30:39.000Z","repository":{"id":42025293,"uuid":"200788258","full_name":"rubocop/minitest-style-guide","owner":"rubocop","description":"Best practices for writing your tests","archived":false,"fork":false,"pushed_at":"2024-04-22T12:56:29.000Z","size":104,"stargazers_count":68,"open_issues_count":4,"forks_count":15,"subscribers_count":13,"default_branch":"master","last_synced_at":"2024-08-07T08:07:59.281Z","etag":null,"topics":["minitest","rubocop","ruby","style-guide"],"latest_commit_sha":null,"homepage":"https://minitest.rubystyle.guide","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rubocop.png","metadata":{"files":{"readme":"README.adoc","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":"bbatsov","patreon":"bbatsov","open_collective":"rubocop","custom":"https://www.paypal.me/bbatsov"}},"created_at":"2019-08-06T06:16:15.000Z","updated_at":"2024-07-29T18:05:59.000Z","dependencies_parsed_at":"2023-12-11T10:49:04.474Z","dependency_job_id":null,"html_url":"https://github.com/rubocop/minitest-style-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubocop%2Fminitest-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubocop%2Fminitest-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubocop%2Fminitest-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rubocop%2Fminitest-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rubocop","download_url":"https://codeload.github.com/rubocop/minitest-style-guide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223336600,"owners_count":17128784,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["minitest","rubocop","ruby","style-guide"],"created_at":"2024-08-06T08:01:11.129Z","updated_at":"2024-11-06T12:24:22.199Z","avatar_url":"https://github.com/rubocop.png","language":null,"funding_links":["https://github.com/sponsors/bbatsov","https://patreon.com/bbatsov","https://opencollective.com/rubocop","https://www.paypal.me/bbatsov","https://www.patreon.com/bbatsov"],"categories":["Others"],"sub_categories":[],"readme":"= Minitest Style Guide\n:idprefix:\n:idseparator: -\n:sectanchors:\n:sectlinks:\n:toc: preamble\n:toclevels: 1\nifndef::backend-pdf[]\n:toc-title: pass:[\u003ch2\u003eTable of Contents\u003c/h2\u003e]\nendif::[]\n:source-highlighter: rouge\n\n== Introduction\n\n[quote, Officer Alex J. Murphy / RoboCop]\n____\nRole models are important.\n____\n\nifdef::env-github[]\nTIP: You can find a beautiful version of this guide with much improved navigation at https://minitest.rubystyle.guide.\nendif::[]\n\nThis Minitest style guide outlines the recommended best practices for real-world programmers to write code that can be maintained by other real-world programmers.\n\nhttps://github.com/rubocop/rubocop[RuboCop], a static code analyzer (linter) and formatter, has a https://github.com/rubocop/rubocop-minitest[`rubocop-minitest`] extension, provides a way to enforce the rules outlined in this guide.\n\nYou can generate a PDF copy of this guide using https://asciidoctor.org/docs/asciidoctor-pdf/[AsciiDoctor PDF], and an HTML copy https://asciidoctor.org/docs/convert-documents/#converting-a-document-to-html[with] https://asciidoctor.org/#installation[AsciiDoctor] using the following commands:\n\n[source,shell]\n----\n# Generates README.pdf\nasciidoctor-pdf -a allow-uri-read README.adoc\n\n# Generates README.html\nasciidoctor\n----\n\n[TIP]\n====\nInstall the `rouge` gem to get nice syntax highlighting in the generated document.\n\n[source,shell]\n----\ngem install rouge\n----\n====\n\n== A Living Document\n\nThis guide is a work in progress - existing guidelines are constantly being improved, new guidelines are added, occasionally some guidelines\nwould get removed.\n\n== Layout\n\nThis section discusses the idiomatic way to structure tests.\n\nNOTE: This section is currently a stub. Contributions welcome!\n\n== Assertions\n\nThis section discusses idiomatic usage of the assertions provided by Minitest.\n\n=== Assert Nil [[assert-nil]]\n\nUse `assert_nil` if expecting `nil`.\n\n[source,ruby]\n----\n# bad\nassert_equal(nil, actual)\n\n# good\nassert_nil(actual)\n----\n\n=== Refute Nil [[refute-nil]]\n\nUse `refute_nil` if not expecting `nil`.\n\n[source,ruby]\n----\n# bad\nassert(!actual.nil?)\nrefute(actual.nil?)\n\n# good\nrefute_nil(actual)\n----\n\n=== Assert Equal Arguments Order[[assert-equal-args-order]]\n\n`assert_equal` should always have expected value as first argument because if the assertion fails the\nerror message would say expected \"rubocop-minitest\" received \"rubocop\" not the other way around.\n\nNOTE: If you're used to working with RSpec then this in the opposite order.\n\n[source,ruby]\n----\n# bad\nassert_equal(actual, \"rubocop-minitest\")\n\n# good\nassert_equal(\"rubocop-minitest\", actual)\n----\n\n=== Refute Equal[[refute-equal]]\n\nUse `refute_equal` if `expected` and `actual` should not be same.\n\n[source,ruby]\n----\n# bad\nassert(\"rubocop-minitest\" != actual)\n\n# good\nrefute_equal(\"rubocop-minitest\", actual)\n----\n\n=== Assert Same [[assert-same]]\n\nUse `assert_same` instead of `assert` with `equal?`.\n\nNOTE: Use `assert_same` only when there is a need to compare by identity. Otherwise, use `assert_equal`.\n\n[source,ruby]\n----\n# bad\nassert(expected.equal?(actual))\n\n# good\nassert_same(expected, actual)\n----\n\n=== Refute Same [[refute-same]]\n\nUse `refute_same` instead of `refute` with `equal?`.\n\nNOTE: Use `refute_same` only when there is a need to compare by identity. Otherwise, use `refute_equal`.\n\n[source,ruby]\n----\n# bad\nrefute(expected.equal?(actual))\nassert(!expected.equal?(actual))\n\n# good\nrefute_same(expected, actual)\n----\n\n=== Assert Truthy [[assert-truthy]]\n\nUse `assert` if expecting truthy value.\n\n[source,ruby]\n----\n# bad\nassert_equal(true, actual)\n\n# good\nassert(actual)\n----\n\n=== Refute false [[refute-false]]\n\nUse `refute` if expecting false.\n\n[source,ruby]\n----\n# bad\nassert_equal(false, actual)\n\n# bad\nassert(!something)\n\n# good\nrefute(actual)\n----\n\n=== Assert Includes [[assert-includes]]\n\nUse `assert_includes` to assert if the object is included in the collection.\n\n[source,ruby]\n----\n# bad\nassert(collection.include?(object))\n\n# good\nassert_includes(collection, object)\n----\n\n=== Refute Includes [[refute-includes]]\n\nUse `refute_includes` if the object is not included in the collection.\n\n[source,ruby]\n----\n# bad\nrefute(collection.include?(object))\nassert(!collection.include?(object))\n\n# good\nrefute_includes(collection, object)\n----\n\n=== Assert In Delta [[assert-in-delta]]\n\nUse `assert_in_delta` if comparing `floats`. Assertion passes if the expected value is within the `delta` of `actual` value.\n\n[source,ruby]\n----\n# bad\nassert_equal(Math::PI, actual)\n\n# good\nassert_in_delta(Math::PI, actual, 0.01)\n----\n\n=== Refute In Delta [[refute-in-delta]]\n\nUse `refute_in_delta` if comparing `floats`. Assertion passes if the expected value is NOT within the `delta` of `actual` value.\n\n[source,ruby]\n----\n# bad\nrefute_equal(Math::PI, actual)\n\n# good\nrefute_in_delta(Math::PI, actual, 0.01)\n----\n\n=== Assert Empty [[assert-empty]]\n\nUse `assert_empty` if expecting object to be empty.\n\n[source,ruby]\n----\n# bad\nassert(object.empty?)\n\n# good\nassert_empty(object)\n----\n\n=== Refute Empty [[refute-empty]]\n\nUse `refute_empty` if expecting object to be not empty.\n\n[source,ruby]\n----\n# bad\nassert(!object.empty?)\nrefute(object.empty?)\n\n# good\nrefute_empty(object)\n----\n\n=== Assert Operator [[assert-operator]]\n\nUse `assert_operator` if comparing expected and actual object using operator.\n\n[source,ruby]\n----\n# bad\nassert(expected \u003c actual)\n\n# good\nassert_operator(expected, :\u003c, actual)\n----\n\n=== Refute Operator [[refute-operator]]\n\nUse `refute_operator` if expecting expected object is not binary operator of the actual object. Assertion passes if the expected object is not binary operator (example: greater than) the actual object.\n\n[source,ruby]\n----\n# bad\nassert(!(expected \u003e actual))\nrefute(expected \u003e actual)\n\n# good\nrefute_operator(expected, :\u003e, actual)\n----\n\n=== Assert Output [[assert-output]]\n\nUse `assert_output` to assert the methods output. Assertion passes if the expected output or error are matched or equal to the standard output/error.\nThe expected value can be a regex, string or nil.\n\n[source,ruby]\n----\n# bad\n$stdout = StringIO.new\nputs object.method\n$stdout.rewind\nassert_match expected, $stdout.read\n\n# good\nassert_output(expected) { puts object.method }\n----\n\n=== Assert Silent [[assert-silent]]\n\nUse `assert_silent` to assert that nothing was written to stdout and stderr.\n\n[source,ruby]\n----\n# bad\nassert_output('', '') { puts object.do_something }\n\n# good\nassert_silent { puts object.do_something }\n----\n\n=== Assert Path Exists [[assert-path-exists]]\n\nUse `assert_path_exists` if expecting path to exist.\n\n[source,ruby]\n----\n# bad\nassert(File.exist?(path))\n\n# good\nassert_path_exists(path)\n----\n\n=== Refute Path Exists [[refute-path-exists]]\n\nUse `refute_path_exists` if expecting path to not exist.\n\n[source,ruby]\n----\n# bad\nassert(!File.exist?(path))\nrefute(File.exist?(path))\n\n# good\nrefute_path_exists(path)\n----\n\n=== Assert Match [[assert-match]]\n\nUse `assert_match` if expecting matcher regex to match actual object.\n\n[source,ruby]\n----\n# bad\nassert(pattern.match?(object))\n\n# good\nassert_match(pattern, object)\n----\n\n=== Refute Match [[refute-match]]\n\nUse `refute_match` if expecting matcher regex to not match actual object.\n\n[source,ruby]\n----\n# bad\nassert(!pattern.match?(object))\nrefute(pattern.match?(object))\n\n# good\nrefute_match(pattern, object)\n----\n\n=== Assert Predicate [[assert-predicate]]\n\nUse `assert_predicate` if expecting to test the predicate on the expected object and on applying predicate returns true.\nThe benefit of using the `assert_predicate` over the `assert` or `assert_equal` is the user friendly\nerror message when assertion fails.\n\n[source,ruby]\n----\n# bad\nassert expected.zero?     # =\u003e Expected false to be truthy\nassert_equal 0, expected  # =\u003e Expected: 0 Actual: 2\n\n# good\nassert_predicate expected, :zero? # =\u003e Expected 2 to be zero?.\n----\n\n=== Refute Predicate [[refute-predicate]]\n\nUse `refute_predicate` if expecting to test the predicate on the expected object and on applying predicate returns false.\n\n[source,ruby]\n----\n# bad\nassert(!expected.zero?)\nrefute(expected.zero?)\n\n# good\nrefute_predicate expected, :zero?\n----\n\n=== Assert Responds To Method [[assert-respond-to]]\n\nUse `assert_respond_to` if expecting object to respond to a method.\n\n[source,ruby]\n----\n# bad\nassert(object.respond_to?(some_method))\n\n# good\nassert_respond_to(object, some_method)\n----\n\n=== Refute Responds To Method [[refute-respond-to]]\n\nUse `refute_respond_to` if expecting object to not respond to a method.\n\n[source,ruby]\n----\n# bad\nassert(!object.respond_to?(some_method))\nrefute(object.respond_to?(some_method))\n\n# good\nrefute_respond_to(object, some_method)\n----\n\n=== Assert Instance Of [[assert-instance-of]]\n\nPrefer `assert_instance_of(class, object)` over `assert(object.instance_of?(class))`.\n\n[source,ruby]\n----\n# bad\nassert('rubocop-minitest'.instance_of?(String))\n\n# good\nassert_instance_of(String, 'rubocop-minitest')\n----\n\n=== Refute Instance Of [[refute-instance-of]]\n\nPrefer `refute_instance_of(class, object)` over `refute(object.instance_of?(class))`.\n\n[source,ruby]\n----\n# bad\nrefute('rubocop-minitest'.instance_of?(String))\n\n# good\nrefute_instance_of(String, 'rubocop-minitest')\n----\n\n=== Assert Kind Of [[assert-kind-of]]\n\nPrefer `assert_kind_of(class, object)` over `assert(object.kind_of?(class))`.\n\n[source,ruby]\n----\n# bad\nassert('rubocop-minitest'.kind_of?(String))\n\n# good\nassert_kind_of(String, 'rubocop-minitest')\n----\n\n=== Refute Kind Of [[refute-kind-of]]\n\nPrefer `refute_kind_of(class, object)` over `refute(object.kind_of?(class))`.\n\n[source,ruby]\n----\n# bad\nrefute('rubocop-minitest'.kind_of?(String))\n\n# good\nrefute_kind_of(String, 'rubocop-minitest')\n----\n\n=== Unspecified exception [[unspecified-exception]]\n\nSpecify the exception being captured by `assert_raises`. This avoids false-positives\nwhen the raised exception is not the same users were expected.\n\n[source,ruby]\n----\n# bad\nassert_raises { do_something }\n\n# good\nassert_raises(FooException) { do_something }\n----\n\n== Expectations\n\nThis section discusses idiomatic usage of the expectations provided by Minitest.\n\nNOTE: This section is currently a stub. Contributions welcome!\n\n=== Global Expectations [[global-expectations]]\n\nUse `_()` wrapper if using global expectations which are deprecated methods.\n\n[source,ruby]\n----\n# bad\ndo_something.must_equal 2\n{ raise_exception }.must_raise TypeError\n\n# good\n_(do_something).must_equal 2\nvalue(do_something).must_equal 2\nexpect(do_something).must_equal 2\n_ { raise_exception }.must_raise TypeError\n----\n\nCheck the http://docs.seattlerb.org/minitest/Minitest/Expectations.html[Minitest::Expectations doc] for more information about its usage.\n\n=== Hooks [[hooks]]\n\nIf using a module containing `setup` or `teardown` methods, be sure to call `super` in the test class `setup` or\n`teardown`.\n\n[source,ruby]\n----\n# bad\nclass TestMeme \u003c Minitest::Test\n  include MyHelper\n\n  def setup\n    do_something\n  end\n\n  def teardown\n    clean_something\n  end\nend\n\n# good\nclass TestMeme \u003c Minitest::Test\n  include MyHelper\n\n  def setup\n    super\n    do_something\n  end\n\n  def teardown\n    clean_something\n    super\n  end\nend\n----\n\n=== Hooks Ordering [[hooks-ordering]]\n\nOrder hooks in the order in which they will be executed.\n\n[source,ruby]\n----\n# bad\nclass SomethingTest \u003c Minitest::Test\n  def teardown; end\n  def setup; end\nend\n\n# good\nclass SomethingTest \u003c Minitest::Test\n  def setup; end\n  def teardown; end\nend\n----\n\n=== Extension Hooks [[extension-hooks]]\n\nThe `before_*` and `after_*` hooks are meant for libraries that extend minitest.\nThey are not meant to be used by test developers.\n\n[source,ruby]\n----\n# bad\nclass SomethingTest \u003c Minitest::Test\n  def before_setup; end\n  def before_teardown; end\n  def after_setup; end\n  def after_teardown; end\nend\n\n# good\nclass SomethingTest \u003c Minitest::Test\n  def setup; end\n  def teardown; end\nend\n----\n\n=== Skipping Runnable Methods [[skipping-runnable-methods]]\n\nPrefer `skip` over `return` for skipping runnable methods that start with `test_`.\n\n[source,ruby]\n----\n# bad\ndef test_something\n  return if condition?\n  assert_equal(42, something)\nend\n\n# good\ndef test_something\n  skip if condition?\n  assert_equal(42, something)\nend\n----\n\n== File Naming [[file-naming]]\n\nUse a consistent naming pattern of either a `test_` prefix or a `_test` suffix for filenames of tests.\n\nFor a Rails app, follow the `_test` suffix convention, as used by the Rails generators.\n\nFor a gem, follow the `test_` prefix convention, as used by the `bundle gem` generator.\n\n== Test Doubles\n\nMinitest includes `minitest/mock`, a simple mock/stub system.\n\n[source,ruby]\n----\n# example\nservice = Minitest::Mock.new\nservice.expect(:execute, true)\n----\n\nA common alternative is https://github.com/freerange/mocha[Mocha].\n\n[source,ruby]\n----\n# example\nservice = mock\nservice.expects(:execute).returns(true)\n----\n\nChoose only one to use – avoid mixing both approaches within one project.\n\n== Subclassing Test Cases\n\nMinitest uses Ruby classes, if a Minitest class inherits from another class, it will also inherit its methods\ncausing Minitest to run the parent's tests twice.\n\n[source,ruby]\n----\n# bad (unless multiple runs are the intended behavior)\nclass ParentTest \u003c Minitest::Test\n  def test_1\n    #... Run twice\n  end\nend\n\nclass ChildTest \u003c ParentTest\n  def test_2\n    #...\n  end\nend\n----\n\nIn rare cases, we may want to run the tests twice, but in general avoid subclassing test cases.\n\nNote: The `minitest/spec` alternative syntax disable inheritance between test classes and so does not have this behavior.\n\n== Related Guides\n\n* https://rubystyle.guide[Ruby Style Guide]\n* https://rails.rubystyle.guide[Rails Style Guide]\n* https://rspec.rubystyle.guide[RSpec Style Guide]\n\n== Contributing\n\nThe guide is still a work in progress - some guidelines are lacking examples, some guidelines don't have examples that illustrate them clearly enough.\nImproving such guidelines is a great (and simple way) to help the Ruby community!\n\nIn due time these issues will (hopefully) be addressed - just keep them in mind for now.\n\nNothing written in this guide is set in stone.\nIt's our desire to work together with everyone interested in Ruby coding style, so that we could ultimately create a resource that will be beneficial to the entire Ruby community.\n\nFeel free to open tickets or send pull requests with improvements.\nThanks in advance for your help!\n\nYou can also support the project (and RuboCop) with financial contributions via https://www.patreon.com/bbatsov[Patreon].\n\n=== How to Contribute?\n\nIt's easy, just follow the contribution guidelines below:\n\n* https://help.github.com/articles/fork-a-repo[Fork] https://github.com/rubocop/minitest-style-guide[rubocop/minitest-style-guide] on GitHub\n* Make your feature addition or bug fix in a feature branch.\n* Include a http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[good description] of your changes\n* Push your feature branch to GitHub\n* Send a https://help.github.com/articles/using-pull-requests[Pull Request]\n\n== License\n\nimage:https://i.creativecommons.org/l/by/3.0/88x31.png[Creative Commons License] This work is licensed under a http://creativecommons.org/licenses/by/3.0/deed.en_US[Creative Commons Attribution 3.0 Unported License]\n\n== Spread the Word\n\nA community-driven style guide is of little use to a community that doesn't know about its existence.\nTweet about the guide, share it with your friends and colleagues.\nEvery comment, suggestion or opinion we get makes the guide just a little bit better.\nAnd we want to have the best possible guide, don't we?\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubocop%2Fminitest-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frubocop%2Fminitest-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frubocop%2Fminitest-style-guide/lists"}