minitest-meaningful 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +76 -0
- data/Rakefile +4 -0
- data/lib/minitest/meaningful/version.rb +7 -0
- data/lib/minitest/meaningful.rb +91 -0
- data/lib/minitest/meaningful_plugin.rb +13 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0537b67234cc8e5b97f42ac7117068392946f88ca607b2b7ff6aa0fff95b7f1f
|
4
|
+
data.tar.gz: 49534eacac48a362598ca178ee5b91da40ab41da44f3ab132aecbdbfeb8d78c7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4248b5451112ca9ff2dd6e96d22404b8b0aa8b4cd23ebf11f6596e365587c1737210ec33680029c3c1b2520d87aa7002f2df71ec00c4f786ea55e0a1f143a4ba
|
7
|
+
data.tar.gz: b777b67082ea2a943b3c01d8fbb9b3760af8c2fdafe00cdec7ce209e0d7f8ab47e94c81c8cea663da0756b77d6f848937364ce9f7604ea63100ea70f8e8d06d8
|
data/README.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# Minitest::Meaningful
|
2
|
+
|
3
|
+
This is a proof-of-concept Minitest plugin to help avoid writing completely meaningless tests. A meaningless test is one that always passes because of incorrect test setup. This plugin helps ensure tests aren't meaningless, by trying to make them fail.
|
4
|
+
|
5
|
+
For example, in a Rails app we might have a test that looks like this:
|
6
|
+
|
7
|
+
```rb
|
8
|
+
test "#visible_comments excludes hidden comments" do
|
9
|
+
post = create(:post)
|
10
|
+
comment = create(:comment, status: "hidden")
|
11
|
+
|
12
|
+
refute_includes post.visible_comments, comment
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
The `comment` record is completely unrelated to the `post` record. It doesn't matter what the `status` is, nor does it really matter what the `#visible_comments` implementation looks like, there's no reason this comment would ever be returned. It always passes, it's a false positive test.
|
17
|
+
|
18
|
+
This plugin adds an `important!` annotation to wrap the most important test setup variable. The test runner can then run the test both with and without evaluating that block. If the test passes when that `important!` block is not evaluated, then we know it is not meaningful.
|
19
|
+
|
20
|
+
```rb
|
21
|
+
test "#visible_comments excludes hidden comments" do
|
22
|
+
post = create(:post)
|
23
|
+
comment = create(:comment)
|
24
|
+
important! { comment.update!(status: "hidden") }
|
25
|
+
|
26
|
+
refute_includes post.visible_comments, comment
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
## Installation
|
31
|
+
|
32
|
+
Install the gem and add to the application's Gemfile by executing:
|
33
|
+
|
34
|
+
$ bundle add minitest-meaningful
|
35
|
+
|
36
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
37
|
+
|
38
|
+
$ gem install minitest-meaningful
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
|
42
|
+
Include the `Minitest::Meaningful` module in your test:
|
43
|
+
|
44
|
+
```rb
|
45
|
+
class ExampleTest > Minitest::Test
|
46
|
+
include Minitest::Meaningful
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Annotate the most important test setup variable:
|
51
|
+
|
52
|
+
```rb
|
53
|
+
def test_visible_comments_excludes_hidden_comments
|
54
|
+
post = create(:post)
|
55
|
+
comment = create(:comment)
|
56
|
+
important! { comment.update!(status: "hidden") }
|
57
|
+
|
58
|
+
refute_includes post.visible_comments, comment
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
Assert the test should fail:
|
63
|
+
|
64
|
+
```rb
|
65
|
+
assert_meaningful :test_visible_comments_excludes_hidden_comments
|
66
|
+
```
|
67
|
+
|
68
|
+
Run the test with the `--meaningful` flag:
|
69
|
+
|
70
|
+
```sh
|
71
|
+
$ ruby example_test.rb --meaningful
|
72
|
+
```
|
73
|
+
|
74
|
+
## Contributing
|
75
|
+
|
76
|
+
This is definitely a hacky proof-of-concept. If you can think of a better way to integrate this into Minitest test suites, or a way to more robustly identify false-positive tests, please let me know! Also, I hate the name—please suggest something better!
|
data/Rakefile
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "meaningful/version"
|
4
|
+
|
5
|
+
module Minitest
|
6
|
+
module Meaningful
|
7
|
+
class << self
|
8
|
+
attr_accessor :enabled
|
9
|
+
end
|
10
|
+
|
11
|
+
MultipleAnnotationsError = Class.new(StandardError)
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def runnable_methods
|
15
|
+
if Meaningful.enabled
|
16
|
+
meaningful_methods.keys
|
17
|
+
else
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def meaningful_methods
|
23
|
+
@meaningful_methods ||= {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def assert_meaningful(*names)
|
27
|
+
names.each do |name|
|
28
|
+
meaningful_methods[name.to_s] = caller
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.included(base)
|
34
|
+
base.extend(ClassMethods)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def run
|
39
|
+
@should_fail = Meaningful.enabled
|
40
|
+
|
41
|
+
super
|
42
|
+
|
43
|
+
if @should_fail
|
44
|
+
if !@important_backtrace
|
45
|
+
exception = Minitest::Assertion.new("Expected test to have `important!` setup.")
|
46
|
+
exception.set_backtrace(self.class.meaningful_methods[name.to_s])
|
47
|
+
self.failures << exception
|
48
|
+
elsif !@did_fail
|
49
|
+
exception = Minitest::Assertion.new("Expected test to fail without `important!` setup.")
|
50
|
+
exception.set_backtrace(@important_backtrace)
|
51
|
+
self.failures << exception
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
Result.from(self)
|
56
|
+
rescue MultipleAnnotationsError
|
57
|
+
exception = Minitest::Assertion.new("Test uses `important!` more than once.")
|
58
|
+
exception.set_backtrace(@important_backtrace)
|
59
|
+
self.failures << exception
|
60
|
+
|
61
|
+
Result.from(self)
|
62
|
+
end
|
63
|
+
|
64
|
+
def capture_exceptions
|
65
|
+
return super unless @should_fail
|
66
|
+
|
67
|
+
yield
|
68
|
+
rescue *Minitest::Test::PASSTHROUGH_EXCEPTIONS
|
69
|
+
raise
|
70
|
+
rescue Assertion => e
|
71
|
+
@did_fail = true
|
72
|
+
end
|
73
|
+
|
74
|
+
def important!
|
75
|
+
if @should_fail
|
76
|
+
if @important_backtrace
|
77
|
+
raise MultipleAnnotationsError
|
78
|
+
else
|
79
|
+
@important_backtrace = caller
|
80
|
+
end
|
81
|
+
else
|
82
|
+
unless self.class.meaningful_methods.keys.include?(name.to_s)
|
83
|
+
exception = Minitest::Assertion.new("Test uses `important!` without `assert_meaningful`.")
|
84
|
+
raise exception
|
85
|
+
end
|
86
|
+
|
87
|
+
yield
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "minitest/meaningful"
|
2
|
+
|
3
|
+
module Minitest
|
4
|
+
def self.plugin_meaningful_options(opts, options)
|
5
|
+
opts.on "--meaningful", "Expect tests not to pass with important test setup removed." do
|
6
|
+
options[:meaningful] = true
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.plugin_meaningful_init(options)
|
11
|
+
Meaningful.enabled = options.fetch(:meaningful, false)
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: minitest-meaningful
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Thomas Marshall
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-04-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: minitest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5'
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- thomas@thomasmarshall.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- README.md
|
35
|
+
- Rakefile
|
36
|
+
- lib/minitest/meaningful.rb
|
37
|
+
- lib/minitest/meaningful/version.rb
|
38
|
+
- lib/minitest/meaningful_plugin.rb
|
39
|
+
homepage: https://github.com/thomasmarshall/minitest-meaningful
|
40
|
+
licenses: []
|
41
|
+
metadata:
|
42
|
+
homepage_uri: https://github.com/thomasmarshall/minitest-meaningful
|
43
|
+
source_code_uri: https://github.com/thomasmarshall/minitest-meaningful
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 2.6.0
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements: []
|
59
|
+
rubygems_version: 3.5.3
|
60
|
+
signing_key:
|
61
|
+
specification_version: 4
|
62
|
+
summary: A minitest plugin to prevent false positive tests.
|
63
|
+
test_files: []
|