grift 3.1.1 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +72 -48
- data/README.md +27 -1
- data/lib/grift/minitest_plugin.rb +153 -1
- data/lib/grift/mock_method.rb +35 -12
- data/lib/grift/version.rb +1 -1
- data/lib/grift.rb +14 -3
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4aff61073e962068bf8db43ccf6b17746c504a889725bbce4a7b545d81acece7
|
|
4
|
+
data.tar.gz: 96239a0ee6e279db817d13cd65566a74c193929e3bafcc8f2a2f2f5a2d594b60
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5bac2eec9ca2ae6a986aa778620eeb3af3b354cd9b63ce8bb94c5b58441be4b1b1a475d079309e03b9a81deec67e5d27dd3eeba3c7434cdea477f5c779763004
|
|
7
|
+
data.tar.gz: dad5770bb188d57df66c438ac77b989ad480cad1936d425394496ad4675b270b1aa6ab56096d633587545972644162db96b466b3751bb0f0968373f1280c6f52
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [3.2.0](https://github.com/clarkedb/grift/compare/v3.1.1...v3.2.0) (2026-10-14)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
* add an instance option to Grift.spy_on ([#308](https://github.com/clarkedb/grift/issues/308)) ([ffaea83](https://github.com/clarkedb/grift/commit/ffaea8395879241906f7fe5b3533647eafd40ea9))
|
|
13
|
+
* add Minitest assertions for mocks ([#312](https://github.com/clarkedb/grift/issues/312)) ([b4b6117](https://github.com/clarkedb/grift/commit/b4b61173489d6fa03e98892eab984d0d225068a0)), closes [#130](https://github.com/clarkedb/grift/issues/130)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
* record keyword arguments for mocked implementations ([#311](https://github.com/clarkedb/grift/issues/311)) ([858873e](https://github.com/clarkedb/grift/commit/858873ed332834f0bfc31ed20fade25209e283e9)), closes [#310](https://github.com/clarkedb/grift/issues/310)
|
|
19
|
+
|
|
7
20
|
## [3.1.1](https://github.com/clarkedb/grift/compare/v3.1.0...v3.1.1) (2026-10-14)
|
|
8
21
|
|
|
9
22
|
|
|
@@ -11,113 +24,124 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
11
24
|
|
|
12
25
|
* package only runtime files in the gem ([#292](https://github.com/clarkedb/grift/issues/292)) ([0e6e3fd](https://github.com/clarkedb/grift/commit/0e6e3fdf2e99696468144ce490b015bdee3f13d4))
|
|
13
26
|
|
|
14
|
-
## [3.1.0](https://github.com/clarkedb/grift/
|
|
27
|
+
## [3.1.0](https://github.com/clarkedb/grift/compare/v3.0.0...v3.1.0) (2026-01-03)
|
|
28
|
+
|
|
15
29
|
|
|
16
30
|
### Added
|
|
17
31
|
|
|
18
|
-
|
|
32
|
+
* Official support for Ruby 4.0 ([#274](https://github.com/clarkedb/grift/pull/274))
|
|
19
33
|
|
|
20
34
|
### Fixed
|
|
21
35
|
|
|
22
|
-
|
|
23
|
-
|
|
36
|
+
* Migrate rubocop setup to use plugins ([#275](https://github.com/clarkedb/grift/pull/275))
|
|
37
|
+
* Use preferred `method_defined?` for style ([#276](https://github.com/clarkedb/grift/pull/276))
|
|
24
38
|
|
|
25
|
-
## [3.0.0](https://github.com/clarkedb/grift/
|
|
39
|
+
## [3.0.0](https://github.com/clarkedb/grift/compare/v2.2.0...v3.0.0) (2024-12-26)
|
|
26
40
|
|
|
27
|
-
### Breaking
|
|
28
41
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
42
|
+
### ⚠ BREAKING CHANGES
|
|
43
|
+
|
|
44
|
+
* All mocks are now scoped to the current thread for thread-safety ([#256](https://github.com/clarkedb/grift/pull/256))
|
|
45
|
+
* For parallelized test suites using processes this is not a breaking change
|
|
46
|
+
* This fixes intermittent test failures sometimes seen when codebases have threads calling mocked methods
|
|
32
47
|
|
|
33
48
|
### Added
|
|
34
49
|
|
|
35
|
-
|
|
36
|
-
|
|
50
|
+
* Official support for Ruby 3.4 ([#257](https://github.com/clarkedb/grift/pull/257))
|
|
51
|
+
* Direct access to mock results/calls without calling `mock` ([#258](https://github.com/clarkedb/grift/pull/258))
|
|
52
|
+
|
|
53
|
+
## [2.2.0](https://github.com/clarkedb/grift/compare/v2.1.0...v2.2.0) (2024-01-13)
|
|
37
54
|
|
|
38
|
-
## [2.2.0](https://github.com/clarkedb/grift/releases/tag/v2.2.0) - 2024-01-13
|
|
39
55
|
|
|
40
56
|
### Added
|
|
41
57
|
|
|
42
|
-
|
|
58
|
+
* Official support for Ruby 3.3 ([#203](https://github.com/clarkedb/grift/pull/203))
|
|
59
|
+
|
|
60
|
+
## [2.1.0](https://github.com/clarkedb/grift/compare/v2.0.1...v2.1.0) (2022-12-27)
|
|
43
61
|
|
|
44
|
-
## [2.1.0](https://github.com/clarkedb/grift/releases/tag/v2.1.0) - 2022-12-27
|
|
45
62
|
|
|
46
63
|
### Added
|
|
47
64
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
65
|
+
* Official support for Ruby 3.2 ([#126](https://github.com/clarkedb/grift/pull/126))
|
|
66
|
+
* Support for finite/self-terminating mocking for more precision in testing where a method may get called multiple times
|
|
67
|
+
* The Grift API now supports `mock_return_value_once`, `mock_return_value_n_times`, and `mock_return_values_in_order` ([#135](https://github.com/clarkedb/grift/pull/135))
|
|
68
|
+
* The Grift API now supports `mock_implementation_once` and `mock_implementation_n_times` ([#136](https://github.com/clarkedb/grift/pull/136))
|
|
69
|
+
|
|
70
|
+
## [2.0.1](https://github.com/clarkedb/grift/compare/v2.0.0...v2.0.1) (2022-03-27)
|
|
52
71
|
|
|
53
|
-
## [2.0.1](https://github.com/clarkedb/grift/releases/tag/v2.0.1) - 2022-03-27
|
|
54
72
|
|
|
55
73
|
### Fixed
|
|
56
74
|
|
|
57
|
-
|
|
58
|
-
|
|
75
|
+
* When spying on a method that takes a block, the block now gets forwarded to the original method ([#78](https://github.com/clarkedb/grift/pull/78))
|
|
76
|
+
* When mocking the implementation, if a block is not provided a `Grift::Error` is raised instead of a `LocalJumpError` ([#77](https://github.com/clarkedb/grift/pull/77))
|
|
77
|
+
|
|
78
|
+
## [2.0.0](https://github.com/clarkedb/grift/compare/v1.1.0...v2.0.0) (2022-03-14)
|
|
59
79
|
|
|
60
|
-
## [2.0.0](https://github.com/clarkedb/grift/releases/tag/v2.0.0) - 2022-03-14
|
|
61
80
|
|
|
62
81
|
This version adds true keyword argument support for Ruby 3. See below for how to handle breaking changes.
|
|
63
82
|
|
|
64
|
-
###
|
|
83
|
+
### ⚠ BREAKING CHANGES
|
|
65
84
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
* Dropped support for Ruby 2.5 ([#69](https://github.com/clarkedb/grift/pull/69))
|
|
86
|
+
* Dropped support for Ruby 2.6 ([#72](https://github.com/clarkedb/grift/pull/72))
|
|
87
|
+
* To support keyword arguments, records of call arguments are no longer stored in simple arrays but in a custom Enumerable ([#72](https://github.com/clarkedb/grift/pull/72))
|
|
88
|
+
* This changes the way that your tests will interact with mock calls
|
|
89
|
+
* When before `calls` returned an array, it returns a `Grift::MockMethod::MockExecutions::MockArguments` object
|
|
90
|
+
* Migrating to maintain previous behavior just requires appending `.args` to `calls[i]`
|
|
72
91
|
|
|
73
92
|
### Added
|
|
74
93
|
|
|
75
|
-
|
|
76
|
-
|
|
94
|
+
* Support for mocking private instance and class methods ([#68](https://github.com/clarkedb/grift/pull/68))
|
|
95
|
+
* Support for mocking methods that take positional and keyword arguments ([#72](https://github.com/clarkedb/grift/pull/72))
|
|
77
96
|
|
|
78
97
|
### Fixed
|
|
79
98
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
* When mocking protected methods, the method now remains protected while mocked and after unmocking ([#68](https://github.com/clarkedb/grift/pull/68))
|
|
100
|
+
* When mocking inherited methods, the method goes back to the ancestor's definition after unmocking ([#69](https://github.com/clarkedb/grift/pull/69))
|
|
101
|
+
* When mocking methods with keyword arugments in Ruby 3.x, no error is thrown ([#72](https://github.com/clarkedb/grift/pull/72))
|
|
102
|
+
|
|
103
|
+
## [1.1.0](https://github.com/clarkedb/grift/compare/v1.0.2...v1.1.0) (2022-02-03)
|
|
83
104
|
|
|
84
|
-
## [1.1.0](https://github.com/clarkedb/grift/releases/tag/v1.1.0) - 2022-02-03
|
|
85
105
|
|
|
86
106
|
This version adds support for Ruby 3.1 and updates various dependencies.
|
|
87
107
|
|
|
88
108
|
### Added
|
|
89
109
|
|
|
90
|
-
|
|
110
|
+
* Support Ruby 3.1 ([#52](https://github.com/clarkedb/grift/pull/52))
|
|
111
|
+
|
|
112
|
+
## [1.0.2](https://github.com/clarkedb/grift/compare/v1.0.1...v1.0.2) (2021-11-11)
|
|
91
113
|
|
|
92
|
-
## [1.0.2](https://github.com/clarkedb/grift/releases/tag/v1.0.2) - 2021-11-11
|
|
93
114
|
|
|
94
115
|
This version fixes a bug that prevented the mocking of methods defined by a class's super class.
|
|
95
116
|
|
|
96
117
|
### Fixed
|
|
97
118
|
|
|
98
|
-
|
|
119
|
+
* Allow mocks of inherited methods ([#34](https://github.com/clarkedb/grift/pull/34))
|
|
120
|
+
|
|
121
|
+
## [1.0.1](https://github.com/clarkedb/grift/compare/v1.0.0...v1.0.1) (2021-11-10)
|
|
99
122
|
|
|
100
|
-
## [1.0.1](https://github.com/clarkedb/grift/releases/tag/v1.0.1) - 2021-11-10
|
|
101
123
|
|
|
102
124
|
This version fixes a bug that prevented most mocking features in Grift from functioning as expected.
|
|
103
125
|
|
|
104
126
|
### Fixed
|
|
105
127
|
|
|
106
|
-
|
|
128
|
+
* Uses relative path for yaml config files ([#28](https://github.com/clarkedb/grift/pull/28))
|
|
129
|
+
|
|
130
|
+
## [1.0.0](https://github.com/clarkedb/grift/compare/v0.1.0...v1.0.0) (2021-11-06)
|
|
107
131
|
|
|
108
|
-
## [1.0.0](https://github.com/clarkedb/grift/releases/tag/v1.0.0) - 2021-11-06
|
|
109
132
|
|
|
110
133
|
The first major version of Grift! 100% documentation and 100% code coverage.
|
|
111
134
|
|
|
112
135
|
### Added
|
|
113
136
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
137
|
+
* Spying on method ([#9](https://github.com/clarkedb/grift/pull/9))
|
|
138
|
+
* Mocking method return values ([#9](https://github.com/clarkedb/grift/pull/9))
|
|
139
|
+
* Mocking method implementation ([#13](https://github.com/clarkedb/grift/pull/13))
|
|
140
|
+
* Restricted methods that cannot be mocked ([#20](https://github.com/clarkedb/grift/pull/20))
|
|
141
|
+
* MiniTest Plugin to use hooks and clean up after tests ([#17](https://github.com/clarkedb/grift/pull/17))
|
|
142
|
+
* Documentation! ([#23](https://github.com/clarkedb/grift/pull/23))
|
|
143
|
+
|
|
144
|
+
## 0.1.0 (2021-10-12)
|
|
120
145
|
|
|
121
|
-
## [0.1.0](https://github.com/clarkedb/grift/releases/tag/v0.1.0) - 2021-10-12
|
|
122
146
|
|
|
123
147
|
The initial version of Grift. This was never intended for use and should be considered **deprecated**.
|
data/README.md
CHANGED
|
@@ -28,7 +28,7 @@ gem install grift
|
|
|
28
28
|
|
|
29
29
|
### MiniTest Plugin
|
|
30
30
|
|
|
31
|
-
We recommend using the plugin so that mocks are cleaned up after each test automatically. To enable the plugin, add the following lines of code to your `test_helper` file.
|
|
31
|
+
We recommend using the plugin so that mocks are cleaned up after each test automatically. The plugin also adds [assertions](#assertions) for mocks. To enable the plugin, add the following lines of code to your `test_helper` file.
|
|
32
32
|
|
|
33
33
|
```ruby
|
|
34
34
|
class Minitest::Test
|
|
@@ -87,6 +87,14 @@ my_spy.mock_implementation do |arg1, arg2, **kwargs|
|
|
|
87
87
|
end
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
+
### Class and instance methods with the same name
|
|
91
|
+
|
|
92
|
+
When a class responds to a method itself, Grift mocks the class method. That includes methods every class has, like `name`, `to_s`, and `==`. To mock the instance method instead, pass `instance: true` to `spy_on`:
|
|
93
|
+
|
|
94
|
+
```ruby
|
|
95
|
+
my_mock = Grift.spy_on(MyClass, :name, instance: true).mock_return_value('mocked')
|
|
96
|
+
```
|
|
97
|
+
|
|
90
98
|
### Chaining
|
|
91
99
|
|
|
92
100
|
You can chain `mock_return_value` and `mock_implementation` after initializing the mock.
|
|
@@ -120,6 +128,24 @@ my_mock.results
|
|
|
120
128
|
#=> ['result1', 'result2']
|
|
121
129
|
```
|
|
122
130
|
|
|
131
|
+
### Assertions
|
|
132
|
+
|
|
133
|
+
With the [MiniTest Plugin](#minitest-plugin) included, you can assert on mocks directly in your tests.
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
assert_mocked MyClass, :my_method
|
|
137
|
+
refute_mocked MyClass, :other_method
|
|
138
|
+
|
|
139
|
+
assert_mock_called my_mock
|
|
140
|
+
refute_mock_called my_mock
|
|
141
|
+
|
|
142
|
+
# passes if any call used exactly these arguments
|
|
143
|
+
assert_mock_called_with my_mock, 'first_arg', key: 'value'
|
|
144
|
+
refute_mock_called_with my_mock, 'other_arg'
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
When an assertion fails, the message lists the calls to the mocked method.
|
|
148
|
+
|
|
123
149
|
## Requirements
|
|
124
150
|
|
|
125
151
|
Grift supports all Ruby versions >= 2.7 (including 4.x versions).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Grift
|
|
4
4
|
##
|
|
5
|
-
# A plugin to clean up mocks after tests in Minitest.
|
|
5
|
+
# A plugin to clean up mocks after tests in Minitest and to assert on mocks.
|
|
6
6
|
# It is recommended that you include this plugin to avoid
|
|
7
7
|
# needing to cleanup the mocks after each test.
|
|
8
8
|
#
|
|
@@ -23,5 +23,157 @@ module Grift
|
|
|
23
23
|
super
|
|
24
24
|
Grift.restore_all_mocks(watch: false)
|
|
25
25
|
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Asserts that the given method is currently mocked.
|
|
29
|
+
#
|
|
30
|
+
# @see Grift.mock_method?
|
|
31
|
+
#
|
|
32
|
+
# @example
|
|
33
|
+
# Grift.spy_on(MyClass, :my_method)
|
|
34
|
+
# assert_mocked(MyClass, :my_method)
|
|
35
|
+
#
|
|
36
|
+
# @param klass [Class] the class of the method to be checked
|
|
37
|
+
# @param method [Symbol] the symbol representing the method to be checked
|
|
38
|
+
# @param msg [String, Proc] a message to show before the failure message
|
|
39
|
+
#
|
|
40
|
+
# @return [true]
|
|
41
|
+
#
|
|
42
|
+
def assert_mocked(klass, method, msg = nil)
|
|
43
|
+
key = Grift::MockMethod.hash_key(klass, method)
|
|
44
|
+
assert Grift.mock_method?(klass, method), message(msg) { "Expected #{key} to be mocked" }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
##
|
|
48
|
+
# Asserts that the given method is not currently mocked.
|
|
49
|
+
#
|
|
50
|
+
# @see Grift.mock_method?
|
|
51
|
+
#
|
|
52
|
+
# @example
|
|
53
|
+
# refute_mocked(MyClass, :my_method)
|
|
54
|
+
#
|
|
55
|
+
# @param klass [Class] the class of the method to be checked
|
|
56
|
+
# @param method [Symbol] the symbol representing the method to be checked
|
|
57
|
+
# @param msg [String, Proc] a message to show before the failure message
|
|
58
|
+
#
|
|
59
|
+
# @return [true]
|
|
60
|
+
#
|
|
61
|
+
def refute_mocked(klass, method, msg = nil)
|
|
62
|
+
key = Grift::MockMethod.hash_key(klass, method)
|
|
63
|
+
refute Grift.mock_method?(klass, method), message(msg) { "Expected #{key} to not be mocked" }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
##
|
|
67
|
+
# Asserts that the mocked method has been called at least once.
|
|
68
|
+
#
|
|
69
|
+
# @example
|
|
70
|
+
# my_mock = Grift.spy_on(MyClass, :my_method)
|
|
71
|
+
# MyClass.my_method
|
|
72
|
+
# assert_mock_called(my_mock)
|
|
73
|
+
#
|
|
74
|
+
# @param mock [Grift::MockMethod] the mock to be checked
|
|
75
|
+
# @param msg [String, Proc] a message to show before the failure message
|
|
76
|
+
#
|
|
77
|
+
# @return [true]
|
|
78
|
+
#
|
|
79
|
+
def assert_mock_called(mock, msg = nil)
|
|
80
|
+
refute mock.empty?, message(msg) { "Expected #{mock} to be called" }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
##
|
|
84
|
+
# Asserts that the mocked method has not been called.
|
|
85
|
+
#
|
|
86
|
+
# @example
|
|
87
|
+
# my_mock = Grift.spy_on(MyClass, :my_method)
|
|
88
|
+
# refute_mock_called(my_mock)
|
|
89
|
+
#
|
|
90
|
+
# @param mock [Grift::MockMethod] the mock to be checked
|
|
91
|
+
# @param msg [String, Proc] a message to show before the failure message
|
|
92
|
+
#
|
|
93
|
+
# @return [true]
|
|
94
|
+
#
|
|
95
|
+
def refute_mock_called(mock, msg = nil)
|
|
96
|
+
failure = message(msg, '') do
|
|
97
|
+
"Expected #{mock} to not be called, but it was called with:\n#{mock_calls_description(mock)}"
|
|
98
|
+
end
|
|
99
|
+
assert mock.empty?, failure
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
##
|
|
103
|
+
# Asserts that the mocked method has been called at least once with exactly the given arguments.
|
|
104
|
+
# Every argument is matched against the calls, so there is no custom message parameter.
|
|
105
|
+
#
|
|
106
|
+
# @example
|
|
107
|
+
# my_mock = Grift.spy_on(MyClass, :my_method)
|
|
108
|
+
# MyClass.my_method('first', second: 2)
|
|
109
|
+
# assert_mock_called_with(my_mock, 'first', second: 2)
|
|
110
|
+
#
|
|
111
|
+
# @param mock [Grift::MockMethod] the mock to be checked
|
|
112
|
+
# @param args [Array] the expected positional arguments
|
|
113
|
+
# @param kwargs [Hash] the expected keyword arguments
|
|
114
|
+
#
|
|
115
|
+
# @return [true]
|
|
116
|
+
#
|
|
117
|
+
def assert_mock_called_with(mock, *args, **kwargs)
|
|
118
|
+
failure = proc do
|
|
119
|
+
expected = "Expected #{mock} to be called with #{mock_call_description(args, kwargs)}"
|
|
120
|
+
if mock.empty?
|
|
121
|
+
"#{expected}, but it was not called."
|
|
122
|
+
else
|
|
123
|
+
"#{expected}, but it was called with:\n#{mock_calls_description(mock)}"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
assert mock_called_with?(mock, args, kwargs), failure
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
##
|
|
130
|
+
# Asserts that the mocked method has not been called with exactly the given arguments.
|
|
131
|
+
# Every argument is matched against the calls, so there is no custom message parameter.
|
|
132
|
+
#
|
|
133
|
+
# @example
|
|
134
|
+
# my_mock = Grift.spy_on(MyClass, :my_method)
|
|
135
|
+
# MyClass.my_method('first', second: 2)
|
|
136
|
+
# refute_mock_called_with(my_mock, 'first', second: 3)
|
|
137
|
+
#
|
|
138
|
+
# @param mock [Grift::MockMethod] the mock to be checked
|
|
139
|
+
# @param args [Array] the positional arguments that should not have been used
|
|
140
|
+
# @param kwargs [Hash] the keyword arguments that should not have been used
|
|
141
|
+
#
|
|
142
|
+
# @return [true]
|
|
143
|
+
#
|
|
144
|
+
def refute_mock_called_with(mock, *args, **kwargs)
|
|
145
|
+
failure = proc { "Expected #{mock} to not be called with #{mock_call_description(args, kwargs)}." }
|
|
146
|
+
refute mock_called_with?(mock, args, kwargs), failure
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
private
|
|
150
|
+
|
|
151
|
+
##
|
|
152
|
+
# Checks if any call to the mock used exactly the given arguments.
|
|
153
|
+
#
|
|
154
|
+
# @return [Boolean]
|
|
155
|
+
#
|
|
156
|
+
def mock_called_with?(mock, args, kwargs)
|
|
157
|
+
mock.calls.any? { |call| args == call.args && kwargs == call.kwargs }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
##
|
|
161
|
+
# Formats the arguments of a call like they would be written in Ruby.
|
|
162
|
+
#
|
|
163
|
+
# @return [String]
|
|
164
|
+
#
|
|
165
|
+
def mock_call_description(args, kwargs)
|
|
166
|
+
values = args.map { |arg| mu_pp(arg) } + kwargs.map { |key, value| "#{key}: #{mu_pp(value)}" }
|
|
167
|
+
"(#{values.join(', ')})"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
##
|
|
171
|
+
# Formats every call to the mock, one per line.
|
|
172
|
+
#
|
|
173
|
+
# @return [String]
|
|
174
|
+
#
|
|
175
|
+
def mock_calls_description(mock)
|
|
176
|
+
mock.calls.map { |call| " #{mock_call_description(call.args, call.kwargs)}" }.join("\n")
|
|
177
|
+
end
|
|
26
178
|
end
|
|
27
179
|
end
|
data/lib/grift/mock_method.rb
CHANGED
|
@@ -40,10 +40,11 @@ module Grift
|
|
|
40
40
|
# @param klass [Class] the class to be mocked
|
|
41
41
|
# @param method_name [Symbol] the method to be mocked
|
|
42
42
|
# @param watch [Boolean] whether to start watching the method
|
|
43
|
+
# @param instance [Boolean] whether to mock the instance method even if the class responds to the method itself
|
|
43
44
|
#
|
|
44
45
|
# @return [Grift::MockMethod]
|
|
45
46
|
#
|
|
46
|
-
def initialize(klass, method_name, watch: true)
|
|
47
|
+
def initialize(klass, method_name, watch: true, instance: false)
|
|
47
48
|
if Grift.restricted_method?(klass, method_name)
|
|
48
49
|
raise(Grift::Error, "Cannot mock restricted method #{method_name} for class #{klass}")
|
|
49
50
|
end
|
|
@@ -55,15 +56,11 @@ module Grift
|
|
|
55
56
|
@cache_method_name = :"#{CACHE_METHOD_PREFIX}_#{method_name}"
|
|
56
57
|
|
|
57
58
|
# class methods are really instance methods of the singleton class
|
|
58
|
-
@class_method = klass.singleton_class
|
|
59
|
-
klass.singleton_class.private_method_defined?(method_name, true)
|
|
59
|
+
@class_method = !instance && defined_on?(klass.singleton_class, method_name)
|
|
60
60
|
|
|
61
61
|
@method_access, @inherited = method_access_definition
|
|
62
62
|
raise(Grift::Error, "Cannot mock unknown method #{method_name} for class #{klass}") unless @method_access
|
|
63
|
-
|
|
64
|
-
if class_instance.method_defined?(@cache_method_name)
|
|
65
|
-
raise(Grift::Error, "Cannot mock already mocked method #{method_name} for class #{klass}")
|
|
66
|
-
end
|
|
63
|
+
raise(Grift::Error, "Cannot mock already mocked method #{method_name} for class #{klass}") if already_mocked?
|
|
67
64
|
|
|
68
65
|
watch_method if watch
|
|
69
66
|
end
|
|
@@ -160,7 +157,7 @@ module Grift
|
|
|
160
157
|
return_value = yield(*args, **kwargs)
|
|
161
158
|
|
|
162
159
|
# record the args passed in the call to the method and the result
|
|
163
|
-
mock_executions.store(args: args, result: return_value)
|
|
160
|
+
mock_executions.store(args: args, kwargs: kwargs, result: return_value)
|
|
164
161
|
return_value
|
|
165
162
|
end
|
|
166
163
|
class_instance.send(@method_access, @method_name)
|
|
@@ -203,7 +200,7 @@ module Grift
|
|
|
203
200
|
return_value = yield(*args, **kwargs)
|
|
204
201
|
|
|
205
202
|
# record the args passed in the call to the method and the result
|
|
206
|
-
mock_executions.store(args: args, result: return_value)
|
|
203
|
+
mock_executions.store(args: args, kwargs: kwargs, result: return_value)
|
|
207
204
|
|
|
208
205
|
clean_mock.call
|
|
209
206
|
|
|
@@ -266,7 +263,7 @@ module Grift
|
|
|
266
263
|
return_value = yield(*args, **kwargs)
|
|
267
264
|
|
|
268
265
|
# record the args passed in the call to the method and the result
|
|
269
|
-
mock_executions.store(args: args, result: return_value)
|
|
266
|
+
mock_executions.store(args: args, kwargs: kwargs, result: return_value)
|
|
270
267
|
|
|
271
268
|
clean_mock.call if mock_executions.count == n
|
|
272
269
|
|
|
@@ -618,8 +615,34 @@ module Grift
|
|
|
618
615
|
# @return [Boolean]
|
|
619
616
|
#
|
|
620
617
|
def method_defined?
|
|
621
|
-
|
|
622
|
-
|
|
618
|
+
defined_on?(class_instance, @method_name, inherit: false)
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
##
|
|
622
|
+
# Checks if the method is already mocked. A class method and an instance method
|
|
623
|
+
# with the same name share a key in the mock store, so mocking either one counts.
|
|
624
|
+
#
|
|
625
|
+
# @return [Boolean]
|
|
626
|
+
#
|
|
627
|
+
def already_mocked?
|
|
628
|
+
owners = [@klass.singleton_class]
|
|
629
|
+
# an object can be mocked directly, and it has no instance methods of its own
|
|
630
|
+
owners << @klass if @klass.is_a?(Module)
|
|
631
|
+
|
|
632
|
+
owners.any? { |owner| defined_on?(owner, @cache_method_name) }
|
|
633
|
+
end
|
|
634
|
+
|
|
635
|
+
##
|
|
636
|
+
# Checks if the owner defines the method with any access (public, protected, private).
|
|
637
|
+
#
|
|
638
|
+
# @param owner [Module] the class or singleton class to check
|
|
639
|
+
# @param method_name [Symbol] the method to look for
|
|
640
|
+
# @param inherit [Boolean] whether to include methods defined by ancestors
|
|
641
|
+
#
|
|
642
|
+
# @return [Boolean]
|
|
643
|
+
#
|
|
644
|
+
def defined_on?(owner, method_name, inherit: true)
|
|
645
|
+
owner.method_defined?(method_name, inherit) || owner.private_method_defined?(method_name, inherit)
|
|
623
646
|
end
|
|
624
647
|
|
|
625
648
|
##
|
data/lib/grift/version.rb
CHANGED
data/lib/grift.rb
CHANGED
|
@@ -25,7 +25,9 @@ module Grift
|
|
|
25
25
|
##
|
|
26
26
|
# Mocks the given method to return the provided value.
|
|
27
27
|
# This is syntactical sugar equivalent to calling
|
|
28
|
-
# +spy_on+ and then +mock_return_value+.
|
|
28
|
+
# +spy_on+ and then +mock_return_value+. To mock an instance method
|
|
29
|
+
# when the class responds to a method of the same name, use +spy_on+
|
|
30
|
+
# with +instance: true+.
|
|
29
31
|
#
|
|
30
32
|
# @example
|
|
31
33
|
# my_mock = Grift.mock(MyClass, :some_method, true)
|
|
@@ -46,18 +48,27 @@ module Grift
|
|
|
46
48
|
# Creates a mock for the given method without mocking
|
|
47
49
|
# the implementation or return values.
|
|
48
50
|
#
|
|
51
|
+
# If the class responds to the method itself, the class method is
|
|
52
|
+
# watched. This includes methods every class has, like +name+,
|
|
53
|
+
# +to_s+, and +==+. Pass +instance: true+ to watch the instance
|
|
54
|
+
# method of the same name instead.
|
|
55
|
+
#
|
|
49
56
|
# @example
|
|
50
57
|
# my_mock = Grift.spy_on(MyClass, :some_method)
|
|
51
58
|
#
|
|
59
|
+
# @example
|
|
60
|
+
# my_mock = Grift.spy_on(MyClass, :name, instance: true)
|
|
61
|
+
#
|
|
52
62
|
# @param klass [Class] the class of the method to be watched
|
|
53
63
|
# @param method [Symbol] the symbol representing the method to be watched
|
|
64
|
+
# @param instance [Boolean] if true, watch the instance method even if the class responds to the method itself
|
|
54
65
|
#
|
|
55
66
|
# @raise [Grift::Error] exception if method is already mocked or does not exist
|
|
56
67
|
#
|
|
57
68
|
# @return [Grift::MockMethod]
|
|
58
69
|
#
|
|
59
|
-
def spy_on(klass, method)
|
|
60
|
-
MockMethod.new(klass, method)
|
|
70
|
+
def spy_on(klass, method, instance: false)
|
|
71
|
+
MockMethod.new(klass, method, instance: instance)
|
|
61
72
|
end
|
|
62
73
|
|
|
63
74
|
##
|