├── VERSION ├── .gitignore ├── Gemfile ├── lib ├── minitest-matchers.rb └── minitest │ ├── matchers │ └── version.rb │ └── matchers.rb ├── .minitest.rb ├── .travis.yml ├── .autotest ├── Manifest.txt ├── Rakefile ├── Gemfile.lock ├── minitest-matchers.gemspec ├── History.txt ├── test └── minitest │ └── matchers_test.rb └── README.md /VERSION: -------------------------------------------------------------------------------- 1 | 1.4.1 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | pkg/ 2 | doc/ 3 | .*.sw* 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /lib/minitest-matchers.rb: -------------------------------------------------------------------------------- 1 | require "minitest/matchers" 2 | -------------------------------------------------------------------------------- /.minitest.rb: -------------------------------------------------------------------------------- 1 | gem "minitest" 2 | require "minitest/autorun" 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 2.3.0 3 | 4 | cache: bundler 5 | script: RUBYOPT="-w $RUBYOPT" bundle exec rake 6 | -------------------------------------------------------------------------------- /lib/minitest/matchers/version.rb: -------------------------------------------------------------------------------- 1 | module Minitest 2 | module Matchers 3 | VERSION = File.read(File.expand_path("../../../../VERSION", __FILE__)).strip 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /.autotest: -------------------------------------------------------------------------------- 1 | # -*- ruby -*- 2 | 3 | require "autotest/restart" 4 | 5 | Autotest.add_hook :initialize do |at| 6 | at.testlib = ".minitest" 7 | at.add_exception "tmp" 8 | end 9 | -------------------------------------------------------------------------------- /Manifest.txt: -------------------------------------------------------------------------------- 1 | .autotest 2 | History.txt 3 | Manifest.txt 4 | README.md 5 | Rakefile 6 | lib/minitest/matchers.rb 7 | lib/minitest-matchers.rb 8 | test/test_minitest_matchers.rb 9 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.libs << 'lib' 6 | t.pattern = 'test/**/*_test.rb' 7 | t.verbose = false 8 | end 9 | 10 | task :default => :test 11 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | minitest-matchers (1.4.1) 5 | minitest (~> 5.0) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | minitest (5.0.6) 11 | rake (10.1.0) 12 | 13 | PLATFORMS 14 | ruby 15 | 16 | DEPENDENCIES 17 | minitest-matchers! 18 | rake 19 | -------------------------------------------------------------------------------- /minitest-matchers.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "minitest/matchers/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "minitest-matchers" 7 | s.version = Minitest::Matchers::VERSION 8 | s.authors = ["Wojciech Mach", "Ryan Davis"] 9 | s.email = ["wojtek@wojtekmach.pl", "ryand-ruby@zenspider.com"] 10 | s.homepage = "" 11 | s.summary = %q{Adds support for RSpec-style matchers} 12 | s.description = s.summary 13 | 14 | s.rubyforge_project = "minitest-matchers" 15 | 16 | s.files = `git ls-files`.split("\n") 17 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 18 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 19 | s.require_paths = ["lib"] 20 | 21 | s.add_dependency "minitest", "~> 5.0" 22 | 23 | s.add_development_dependency "rake" 24 | end 25 | -------------------------------------------------------------------------------- /History.txt: -------------------------------------------------------------------------------- 1 | === HEAD 2 | 3 | === 1.4.1 / 2013-10-07 4 | 5 | * 1 bug fix: 6 | 7 | * require 'minitest/matchers' causes uninitialized constant Minitest::Matchers error [thanks @fabiolnm] 8 | 9 | === 1.4.0 / 2013-06-30 10 | 11 | * 1 major enhancements 12 | 13 | * Update for Minitest 5.0 [elskwid] 14 | 15 | === 1.3.0 / 2013-04-22 16 | 17 | * 2 major enhancements 18 | 19 | * New home: github.com/wojtekmach/minitest-matchers 20 | * Depend on minitest ~> 4.7 21 | 22 | === 1.1.3 / 2011-12-18 23 | 24 | * 1 major enhancement 25 | 26 | * Add ::register_matcher 27 | 28 | * 1 minor enhancement 29 | 30 | * First check for Matcher#failure_message_for_should 31 | 32 | === 1.1.3 / 2011-12-18 33 | 34 | * 1 minor enhancement 35 | 36 | * Update Manifest.txt so that it includes lib/minitest-matchers.rb 37 | 38 | === 1.1.2 / 2011-11-22 39 | 40 | * 2 minor enhancement 41 | 42 | * Restore class level must and wont 43 | * Don't check for implicit subject. It's implicit 44 | 45 | === 1.1.1 / 2011-11-18 46 | 47 | * 1 minor enhancement 48 | 49 | * Fix wrong failure message 50 | 51 | === 1.1.0 / 2011-11-18 52 | 53 | * 1 major enhancement 54 | 55 | * Refactored to only support instance level `it` and dropped class level 56 | `must` and `wont`. It's better that way. 57 | 58 | === 1.0.3 / 2011-09-05 59 | 60 | * 1 minor enhancement 61 | 62 | * Depend on minitest >= 2.5.0 63 | 64 | === 1.0.2 / 2011-09-04 65 | 66 | * 1 minor enhancement 67 | 68 | * Fix typo 69 | 70 | === 1.0.1 / 2011-09-04 71 | 72 | * 1 minor enhancement 73 | 74 | * Match first, then set failure message. 75 | 76 | === 1.0.0 / 2011-08-30 77 | 78 | * 1 major enhancement 79 | 80 | * Birthday! 81 | 82 | -------------------------------------------------------------------------------- /test/minitest/matchers_test.rb: -------------------------------------------------------------------------------- 1 | gem "minitest" 2 | require "minitest/autorun" 3 | require "minitest/matchers" 4 | 5 | class BadMatcher; end 6 | 7 | class KindOfMatcher 8 | def initialize klass 9 | @klass = klass 10 | end 11 | 12 | def description 13 | "be kind of #{@klass}" 14 | end 15 | 16 | def matches? subject 17 | subject.kind_of? @klass 18 | end 19 | 20 | def failure_message_for_should 21 | "expected to " + description 22 | end 23 | 24 | def failure_message_for_should_not 25 | "expected not to " + description 26 | end 27 | end 28 | 29 | def be_kind_of klass 30 | KindOfMatcher.new klass 31 | end 32 | 33 | describe Minitest::Test do 34 | it "needs to verify assert_must" do 35 | assert_must(be_kind_of(Array), []).must_equal true 36 | proc { assert_must be_kind_of(String), [] }.must_raise Minitest::Assertion 37 | end 38 | 39 | it "needs to verify assert_wont" do 40 | assert_wont(be_kind_of(String), []).must_equal false 41 | proc { assert_wont be_kind_of(Array), [] }.must_raise Minitest::Assertion 42 | end 43 | end 44 | 45 | describe Minitest::Test, :register_matcher do 46 | Minitest::Test.register_matcher KindOfMatcher, :my_kind_of, :be_my_kind_of 47 | Minitest::Test.register_matcher :be_kind_of, :meth_kind_of, :meth_my_kind_of 48 | 49 | it "needs to verify assert_" do 50 | assert_my_kind_of("", String).must_equal true 51 | proc { assert_my_kind_of [], String }.must_raise Minitest::Assertion 52 | end 53 | 54 | it "needs to verify must_" do 55 | "".must_be_my_kind_of(String).must_equal true 56 | proc { [].must_be_my_kind_of String }.must_raise Minitest::Assertion 57 | end 58 | 59 | it "needs to verify refute_" do 60 | refute_my_kind_of("", Array).must_equal false 61 | proc { refute_my_kind_of [], Array }.must_raise Minitest::Assertion 62 | end 63 | 64 | it "needs to verify wont" do 65 | "".wont_be_my_kind_of(Array).must_equal false 66 | proc { [].wont_be_my_kind_of(Array) }.must_raise Minitest::Assertion 67 | end 68 | 69 | it "accepts method as matcher" do 70 | assert_meth_kind_of("", String).must_equal true 71 | proc { assert_meth_kind_of [], String }.must_raise Minitest::Assertion 72 | refute_meth_kind_of("", Array).must_equal false 73 | proc { refute_my_kind_of [], Array }.must_raise Minitest::Assertion 74 | end 75 | end 76 | 77 | describe Minitest::Spec do 78 | it "needs to verify must" do 79 | [].must(be_kind_of(Array)).must_equal true 80 | proc { [].must be_kind_of(String) }.must_raise Minitest::Assertion 81 | end 82 | 83 | it "needs to verify wont" do 84 | [].wont(be_kind_of(String)).must_equal false 85 | proc { [].wont be_kind_of(Array) }.must_raise Minitest::Assertion 86 | end 87 | 88 | describe "implicit subject" do 89 | subject { [1, 2, 3] } 90 | 91 | must { be_kind_of(Array) } 92 | wont { be_kind_of(String) } 93 | 94 | it "verifies must" do 95 | must be_kind_of(Array) 96 | proc { must be_kind_of(String) }.must_raise Minitest::Assertion 97 | end 98 | 99 | it "verifies wont" do 100 | wont be_kind_of(String) 101 | proc { wont be_kind_of(Array) }.must_raise Minitest::Assertion 102 | end 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # minitest-matchers 2 | 3 | http://github.com/wojtekmach/minitest-matchers 4 | 5 | [![Build Status](https://secure.travis-ci.org/wojtekmach/minitest-matchers.png?branch=master)](http://travis-ci.org/wojtekmach/minitest-matchers) 6 | 7 | ## Warning 8 | 9 | Don't use it! Writing simple assertions (and Minitest way of transforming them to expectations) is almost always a better idea anyway. Work with your favourite library authors to start with assertions and add matchers for convenience and not the other way around. Keep it simple. 10 | 11 | For simple assertions that adhere to the matcher spec, but without all the expectation _infections_, see **[minitest-matchers_vaccine](https://github.com/rmm5t/minitest-matchers_vaccine)**. 12 | 13 | ## Description 14 | 15 | minitest-matchers adds support for RSpec/Shoulda-style matchers to 16 | minitest/unit and minitest/spec. 17 | 18 | More information about matchers can be found here: 19 | 20 | * https://www.relishapp.com/rspec/rspec-expectations 21 | * http://railscasts.com/episodes/157-rspec-matchers-macros 22 | 23 | For use with Rails check out (ValidAttribute + Capybara): 24 | 25 | * https://github.com/wojtekmach/minitest-rails-example 26 | 27 | ## Features/Problems 28 | 29 | * Enables you to use existing matcher classes from projects like 30 | valid\_attribute and capybara 31 | * Can be used both in Minitest::Test & Minitest::Spec 32 | 33 | ## Synopsis 34 | 35 | see example matcher: [matcher.rb](https://github.com/bcardarella/valid_attribute/blob/master/lib/valid_attribute/matcher.rb) 36 | 37 | ```ruby 38 | require "minitest/matchers" 39 | require "minitest/autorun" 40 | require "valid_attribute" 41 | require "active_model" 42 | 43 | class Post 44 | include ActiveModel::Validations 45 | attr_accessor :title 46 | validates :title, :presence => true, :length => 4..20 47 | end 48 | 49 | # Using minitest/unit 50 | 51 | class PostTest < Minitest::Test 52 | include ValidAttribute::Method 53 | 54 | def test_validations 55 | post = Post.new 56 | 57 | assert_must have_valid(:title).when("Good"), post 58 | assert_wont have_valid(:title).when(""), post 59 | end 60 | end 61 | 62 | # Using minitest/spec 63 | 64 | describe Post do 65 | include ValidAttribute::Method 66 | 67 | it "should have validations" do 68 | post = Post.new 69 | 70 | post.must have_valid(:title).when("Good") 71 | post.wont have_valid(:title).when("") 72 | end 73 | end 74 | 75 | # Using minitest/spec with subject 76 | 77 | describe Post do 78 | subject { Post.new } 79 | 80 | it { must have_valid(:title).when("Hello") } 81 | it { wont have_valid(:title).when("", nil, "Bad") } 82 | end 83 | 84 | # or 85 | 86 | describe Post do 87 | subject { Post.new } 88 | 89 | must { have_valid(:title).when("Hello") } 90 | wont { have_valid(:title).when("", nil, "Bad") } 91 | end 92 | ``` 93 | 94 | You can also register matcher so that it works similar to built-in 95 | assertions and expectations. Note subject must be the first argument in assertion. 96 | 97 | ```ruby 98 | Minitest::Test.register_matcher HaveContent, :have_content 99 | Minitest::Test.register_matcher :have_selector, :have_selector 100 | 101 | assert_have_content page, "Hello" 102 | assert_have_selector page, :xpath, "//table/tr" 103 | 104 | page.must_have_content "Hello" 105 | page.must_have_selector :xpath, "//table/tr" 106 | ``` 107 | 108 | ## Requirements 109 | 110 | * `minitest ~> 5.0` 111 | 112 | ## Install 113 | 114 | ``` 115 | gem install minitest-matchers 116 | ``` 117 | 118 | or add to Gemfile: 119 | 120 | ```ruby 121 | group :test do 122 | gem 'minitest-matchers' 123 | end 124 | ``` 125 | 126 | ## License 127 | 128 | (The MIT License) 129 | 130 | Copyright (c) Ryan Davis, seattle.rb, Wojciech Mach 131 | 132 | Permission is hereby granted, free of charge, to any person obtaining 133 | a copy of this software and associated documentation files (the 134 | 'Software'), to deal in the Software without restriction, including 135 | without limitation the rights to use, copy, modify, merge, publish, 136 | distribute, sublicense, and/or sell copies of the Software, and to 137 | permit persons to whom the Software is furnished to do so, subject to 138 | the following conditions: 139 | 140 | The above copyright notice and this permission notice shall be 141 | included in all copies or substantial portions of the Software. 142 | 143 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 144 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 145 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 146 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 147 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 148 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 149 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 150 | -------------------------------------------------------------------------------- /lib/minitest/matchers.rb: -------------------------------------------------------------------------------- 1 | require "minitest/spec" 2 | 3 | module MiniTest 4 | module Assertions 5 | ## 6 | # Fails unless matcher.matches?(subject) returns true 7 | # 8 | # Example: 9 | # 10 | # def test_validations 11 | # assert_must be_valid, @user 12 | # end 13 | 14 | def assert_must matcher, subject, msg = nil 15 | result = matcher.matches? subject 16 | 17 | msg = message(msg) do 18 | if matcher.respond_to? :failure_message_for_should 19 | matcher.failure_message_for_should 20 | else 21 | matcher.failure_message 22 | end 23 | end 24 | 25 | assert result, msg 26 | end 27 | 28 | ## 29 | # Fails if matcher.matches?(subject) returns true 30 | # 31 | # Example: 32 | # 33 | # def test_validations 34 | # assert_wont be_valid, @user 35 | # end 36 | 37 | def assert_wont matcher, subject, msg = nil 38 | msg = message(msg) do 39 | if matcher.respond_to? :failure_message_for_should_not 40 | matcher.failure_message_for_should_not 41 | else 42 | matcher.negative_failure_message 43 | end 44 | end 45 | 46 | if matcher.respond_to? :does_not_match? 47 | assert matcher.does_not_match?(subject), msg 48 | else 49 | refute matcher.matches?(subject), msg 50 | end 51 | end 52 | end 53 | 54 | module Expectations 55 | ## 56 | # See Minitest::Assertions#assert_must 57 | # 58 | # user.must have_valid(:email).when("user@example.com") 59 | # 60 | # :method: must 61 | 62 | infect_an_assertion :assert_must, :must 63 | 64 | ## 65 | # See Minitest::Assertions#assert_wont 66 | # 67 | # user.wont have_valid(:email).when("bad@email") 68 | # 69 | # :method: wont 70 | 71 | infect_an_assertion :assert_wont, :wont 72 | end 73 | end 74 | 75 | class Minitest::Spec 76 | ## 77 | # Expects that matcher matches the subject 78 | # 79 | # Example: 80 | # 81 | # describe Post do 82 | # subject { Post.new } 83 | # 84 | # must { have_valid(:title).when("Good") } 85 | # end 86 | def self.must(&block) 87 | it { subject.must instance_eval(&block) } 88 | end 89 | 90 | ## 91 | # Expects that matcher does not match the subject 92 | # 93 | # Example: 94 | # 95 | # describe Post do 96 | # subject { Post.new } 97 | # 98 | # wont { have_valid(:title).when("Bad") } 99 | # end 100 | def self.wont(&block) 101 | it { subject.wont instance_eval(&block) } 102 | end 103 | 104 | ## 105 | # Define a `must` expectation for implicit subject 106 | # 107 | # Example: 108 | # 109 | # describe Post do 110 | # subject { Post.new } 111 | # 112 | # it { must have_valid(:title).when("Good") } 113 | # end 114 | 115 | def must(*args, &block) 116 | subject.must(*args, &block) 117 | end 118 | 119 | ## 120 | # Define a `wont` expectation for implicit subject 121 | # 122 | # Example: 123 | # 124 | # describe Post do 125 | # subject { Post.new } 126 | # 127 | # it { wont have_valid(:title).when("") } 128 | # end 129 | 130 | def wont(*args, &block) 131 | subject.wont(*args, &block) 132 | end 133 | end 134 | 135 | class Minitest::Test 136 | ## 137 | # Defines assert_* assertion and must_* expectation for a matcher 138 | # 139 | # Example: 140 | # 141 | # # Say you're implementing Capybara's HaveContent matcher 142 | # 143 | # class HaveContent 144 | # # ... 145 | # end 146 | # 147 | # Minitest::Test.register_matcher HaveContent, :have_content 148 | # 149 | # class MyTest < Minitest::Test 150 | # def test_index 151 | # visit "/" 152 | # assert_have_content page, "Hello" 153 | # assert_have_selector page, :xpath, "//table/tr" 154 | # end 155 | # end 156 | # 157 | # describe "my test" do 158 | # test "index" do 159 | # visit "/" 160 | # page.must_have_content "Hello" 161 | # page.must_have_selector :xpath, "//table/tr" 162 | # 163 | # # if you set `page` to be implicit subject, following works too: 164 | # must_have_content "Hello" 165 | # end 166 | # end 167 | # 168 | 169 | def self.register_matcher matcher, name, exp_name=name 170 | define_method :"assert_#{name}" do |*args| 171 | subject = args.shift 172 | 173 | x = if Symbol === matcher 174 | send matcher, *args 175 | else 176 | matcher.new(*args) 177 | end 178 | 179 | assert_must x, subject 180 | end 181 | 182 | Object.infect_an_assertion :"assert_#{name}", :"must_#{exp_name}", true 183 | 184 | define_method :"refute_#{name}" do |*args| 185 | subject = args.shift 186 | 187 | x = if Symbol === matcher 188 | send matcher, *args 189 | else 190 | matcher.new(*args) 191 | end 192 | 193 | assert_wont x, subject 194 | end 195 | 196 | Object.infect_an_assertion :"refute_#{name}", :"wont_#{exp_name}", true 197 | end 198 | end 199 | --------------------------------------------------------------------------------